Appearance
JAVA的反射机制
1、什么是JAVA的反射机制
Java 反射是 Java 被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运 行时透过 Reflection APIs 取得任何一个已知名称的 class 的内部信息,包括其
modifiers(诸如 public, static 等)、superclass(例如 Object)、实现之 interfaces(例如 Cloneable),也包括 fields 和 methods 的所有信息,并可于运行 时改变 fields 内容或唤起 methods。
Java 反射机制容许程序在运行时加载、探知、使用编译期间完全未知的 classes。
换言之,Java 可以加载一个运行时才得知名称的 class,获得其完整结构。
2、JDK 中提供的 Reflection API
Java 反射相关的 API 在包 java.lang.reflect
中
API | 描述 |
---|---|
Member 接口 | 该接口可以获取有关类成员(域或者方法)后者构造函数的信息。 |
AccessibleObject 类 | 该类是域(field)对象、方法(method)对象、构造函数(constructor)对象的基础类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控 制检查的能力。 |
Array 类 | 该类提供动态地生成和访问 JAVA 数组的方法。 |
Constructor 类 | 提供一个类的构造函数的信息以及访问类的构造函数的接口。 |
Field 类 | 提供一个类的域的信息以及访问类的域的接口。 |
Method 类 | 提供一个类的方法的信息以及访问类的方法的接口。 |
Modifier类 | 提供了 static 方法和常量,对类和成员访问修饰符进行解码。 |
Proxy 类 | 提供动态地生成代理类和类实例的静态方法。 |
3、JAVA 反射机制提供了什么功能
Java 反射机制提供如下功能:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判段任意一个类所具有的成员变量和方法
- 在运行时调用任一个对象的方法
- 在运行时创建新类对象
- 在使用 Java 的反射功能时,基本首先都要获取类的 Class 对象,再通过 Class 对象获取其他的对象。
1、获取类的 Class 对象
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。获取类的 Class 对象有多种方式:
1、调用 getClass
java
Boolean var1 = true;
Class<?> classType2 = var1.getClass();
System.out.println(classType2);
// 输出:class java.lang.Boolean
2、运用 .class
java
Class<?> classType4 = Boolean.class;
System.out.println(classType4);
// 输出:class java.lang.Boolean
3、运用 static method Class.forName()
java
Class<?> classType5 = Class.forName("java.lang.Boolean");
System.out.println(classType5);
// 输出:class java.lang.Boolean
4、运用primitive wrapper classes classes语法
java
Class<?> classType3 = Boolean.TYPE;
System.out.println(classType3);
// 输出:boolean
// 这里返回的是 原生类型,和 Boolean.class 返回的不同
2、获取类的 Fields
可以通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值。
JAVA 的 Class<T>类提供了几个方法获取类的属性。
方法 | 描述 |
---|---|
public Field getField(String name) | 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段 |
public Field[] getFields() | 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段 |
public Field getDeclaredField(String name) | 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段 |
public Field[] getDeclared Fields() | 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段 |
java
public class Person {
private String name;
public int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private Person(String name) {
this.name = name;
}
public Person() {
System.out.println("Person()");
}
public void show(){
System.out.println("你好,我是一个人");
}
private String showNation(String nation){
System.out.println("我的国籍是:" + nation);
return nation;
}
}
java
Class<?> clazz = Person.class;
//getFields():获取当前运行时类及其父类中声明为public访问权限的属性
Field[] fields = clazz.getFields();
for(Field f : fields){
System.out.println(f);
}
//getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
System.out.println(f);
}
可见 getFields 和 getDeclaredFields 区别:
- getFields 返回的是申明为 public 的属性,包括父类中定义,
- getDeclaredFields 返回的是指定类定义的所有定义的属性,不包括父类的。
3、获取类的 Method
通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法
方法 | 描述 |
---|---|
public Method getMethod(String name,Class<?>... parameterTypes) | 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公 共成员方法 |
public Method[] getMethods() | 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表 示的类或接口(包括那些由该类或接口声明的以及从超 类和超接口继承的那些的类或接口)的公共 member 方法 |
public Method getDeclared Method(String name,Class<?> ... parameterTypes) | 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指 定已声明方法 |
public Method[] getDeclaredMethods() | 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接 口声明的所有方法,包括公共、保护、默认(包)访问 和私有方法,但不包 括继承的方法 |
java
Class clazz = Person.class;
//getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
Method[] methods = clazz.getMethods();
for(Method m : methods){
System.out.println(m);
}
System.out.println();
//getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
Method[] declaredMethods = clazz.getDeclaredMethods();
for(Method m : declaredMethods){
System.out.println(m);
}
4、获取类的 Constructor
通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例
方法 | 描述 |
---|---|
public Constructor<T> getConstructor(Class<?>... parameterTypes) | 返回一个Constructor对象,它反映此 Class 对象所表示的类的指定公共构造方法 |
public Constructor<?> [] getConstructors() | 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class对象所表示的类的所有公共构造方法 |
public Constructor<?> getDeclaredConstruct or(Class<?>... parameterTypes) | 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法 |
public Constructor<?>[] getDeclaredConstructors() | 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声 明的所 有构造方法 。它们是公共 、保护 、默认( 包 )访问和私有构造方法 |
java
Class clazz = Person.class;
//getConstructors():获取当前运行时类中声明为public的构造器
Constructor[] constructors = clazz.getConstructors();
for(Constructor c : constructors){
System.out.println(c);
}
//getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for(Constructor c : declaredConstructors){
System.out.println(c);
}
5、新建类的实例
1、调用类的 Class 对象的 newInstance 方法,该方法会调用对象的默认
java
Class<Person> clazz = Person.class;
/*
newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。
要想此方法正常的创建运行时类的对象,要求:
1.运行时类必须提供空参的构造器
2.空参的构造器的访问权限得够。通常,设置为public。
在javabean中要求提供一个public的空参构造器。原因:
1.便于通过反射,创建运行时类的对象
2.便于子类继承此运行时类时,默认调用super()时,保证父类有此构造器
*/
Person obj = clazz.newInstance();
System.out.println(obj);
2、调用默认 Constructor 对象的 newInstance 方法
java
Class clazz = Person.class;
Constructor constructor = clazz.getConstructor();
Object instance = constructor.newInstance();
3、调用带参数 Constructor 对象的 newInstance 方法
java
Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);
Object newInstance = declaredConstructor.newInstance("12", 12);
6、调用类的函数
通过反射获取类 Method 对象,调用 Field 的 Invoke 方法调用函数。
java
//调用方法
Method show = clazz.getDeclaredMethod("show");
show.invoke(p);
//通过反射,可以调用Person类的私有结构的。比如:私有的构造器、方法、属性
//调用私有的构造器
Constructor cons1 = clazz.getDeclaredConstructor(String.class);
cons1.setAccessible(true);
Person p1 = (Person) cons1.newInstance("Jerry");
System.out.println(p1);
//调用私有的方法
Method showNation = clazz.getDeclaredMethod("showNation", String.class);
showNation.setAccessible(true);
String nation = (String) showNation.invoke(p1,"中国");//相当于String nation = p1.showNation("中国")
System.out.println(nation);
7、设置/获取类的属性值
通过反射获取类的 Field 对象,调用 Field 方法设置或获取值
java
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//获取指定的属性:要求运行时类中属性声明为public
//通常不采用此方法
Field id = clazz.getField("id");