一、反射
1.1 Java 反射概述
1.1.1什么是反射
-
Java 反射有以下3个动态特性
- 运行时创建实例
- 运行期间调用方法
- 运行时更改属性
-
反射机制允许 Java 程序加载一个运行时才得知其名称的类,获悉其完整 API 信息,包括修饰符(诸如 public、static 等)、超类、实现的接口,也包括属性和方法的所有信息;
-
并可生成其实例、对其属性赋值或调用其方法。
-
通过 Java 反射可以实现一下功能。
- 在运行时探知任意一个实例所属的类。
- 在运行时构造任意一个类的实例。
- 在运行时探知任意一个类所具有的方法和属性。
- 在运行时调用任意一个实例的方法。
1.1.2 Java 反射常用API
- Java 反射技术,常用的类:
- java.lang.Class类:反射的核心类,反射所有的操作都是围绕该类来生成的。通过 Class 类可以获取类的属性、方法等内容信息。
- java.lang.reflect.Constructor类:表示类的构造方法。
- java.lang.reflect.Field 类:表示类的属性,可以获取和设置类中的属性的值。
- java.lang.reflect.Method 类:表示类的方法,可以用来获取类中方法的信息或执行方法。
1.2 反射的应用
- Java 程序中使用反射的基本步骤:
- 导入 java.lang.reflect 包中的相关类。
- 获得需要操作的类的 Class 实例。
- 调用 Class 实例的方法获取 Field、Method 等实例。
- 使用反射 API 操作实例成员。
1.2.1 获取类的信息
- 一个类或接口被加载后,从系统中都能获得一个代表该类或接口的 Class 类型的实例,通过该实例就可以访问到 Java 虚拟机中的这个类或接口。
- 获取 Class 实例
Java 程序中获得 Class 实例通常有三种方式。
-
调用类或接口实例的 getClass() 方法
- getClass() 方法是 java.lang.Object 类中的一个方法,所有类和接口的实例都可以调用该方法
- 该方法会返回该实例的所属类型所对应的 Class 实例。
Class clz = obj.getClass(); //obj为某个类型的实例
-
调用类或接口的 class 属性。
- 在某些类或接口没有实例或无法创建实例的情况下,可以通过其 class 属性获取所对应的 Class 实例。
- 这种方式需要在编译期就知道类或接口的名称。
Class clz = Student.class;//Student 为自定义的学生类型
- Student.class 将会返回 Student 类对应的 Class 类型的实例。
-
使用 Class.forName() 方法。
- 该方法是静态方法,需要传入字符串,字符串参数的值是 类所在的位置
Class clz = Class.forName("com.mysql.cj.jdbc.Driver")
- 从 Class 实例获取信息
方法 | 说明 |
---|---|
String getName() | 以字符串形式返回该类型的名称 |
String getSimpleName() | 以字符串形式返回该类型的简称 |
Package getPackage() | 获取该类型所在的包 |
Class getSuperclass() | 返回该类型的超类的 Class 实例 |
Class [] getInterfaces() | 返回该类型所实现的全部接口的 Class 实例 |
int getModifiers() | 返回该类型的所有修饰符,由访问修饰符对应的 int 常量组成 |
Class [] getDeclaredClasses() | 返回该类型中包含的全部类的Class 实例 |
Class getDeclaringClass() | 返回该类型所在的外部类的 Class 实例 |
- 创建一个基类 BaseClass
public class BaseClass {
}
- 创建 Person 类继承 BaseClass
public final class Person extends BaseClass implements java.io.Serializable{
private String name;
static final int age=30;
protected String address;
public String message;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name, String address, String message) {
this.name = name;
this.address = address;
this.message = message;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", message='" + message + '\'' +
'}';
}
private void silentMethod() throws IOException,NullPointerException {
System.out.println("这是悄悄话");
}
}
- 创建测试类
public class Test {
public static void main(String[] args) {
Class c1= Person.class;
String fullName=c1.getName();
String simpleName=c1.getSimpleName();
System.out.println("以下是"+fullName+"类的基本信息");
System.out.println("--------------------------------");
//获取 Person 类所在的包
Package pkg=c1.getPackage();
System.out.println(simpleName+"定义在"+pkg.getName()+"包中");
System.out.println("--------------------------------");
//获得 c1 所表示的实体(类、接口、基本类型或void)的父类的 Class
//如果 c1 表示 Object 类、一个接口、一个基本类型或 void,则返回 null
//如果 c1 表示一个数组类,则返回表示 Object 类的 Class 实例
Class superClass = c1.getSuperclass();
System.out.println(simpleName+"类的父类是"+superClass.getName());
System.out.println("--------------------------------");
//获得 c1 所表示的类实现的接口
//如果 c1 表示一个不实现任何接口的类或接口,则此方法返回一个长度为 0 的数组
//如果 c1 表示一个基本类型或 void,则此方法返回一个长度为 0 的数组
Class [] interfaces=c1.getInterfaces();
System.out.println(simpleName+"类所实现的接口:"<