抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

认识反射和Class类 + 访问对象的字段 + 调用对象的方法 + 调用构造函数 + 获取继承关系 + 动态代理

认识反射和Class类

反射(Reflection),Java的反射是指程序在运行期可以拿到一个对象的所有信息。

JVM为每个加载的 classinterface创建了对应的 Class实例来保存 classinterface的所有信息;这里的 Class类型是一个名叫 Classclass

获取一个 class对应的 Class实例后,就可以获取该 class的所有信息;

通过 Class 实例获取 class 信息的方法称为反射(Reflection);

JVM总是动态加载class,可以在运行期根据条件来控制加载class。

访问对象的字段

Java的反射API提供的Field类封装了字段的所有信息:

通过Class实例的方法可以获取Field实例:

  • Field getField(name):根据字段名获取某个public的field(包括父类)
  • Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
  • Field[] getFields():获取所有public的field(包括父类)
  • Field[] getDeclaredFields():获取当前类的所有field(不包括父类)

通过Field实例可以获取字段信息:

  • getName():返回字段名称,例如,”name”;
  • getType():返回字段类型,也是一个Class实例,例如,String.class;
  • getModifiers():返回字段的修饰符,它是一个int,不同的bit表示不同的含义。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.lang.reflect.Field;

public class Main {
public static void main(String[] args) throws Exception{
// 拿到实例的字段
Class std= Student.class;
System.out.println(std.getField("score"));
System.out.println(std.getField("name"));
System.out.println(std.getDeclaredField("grade"));
// 拿到实例字段对应的值。
Object p= new Student(45);
Class c=p.getClass();
Field f=c.getDeclaredField("score");
Object value =f.get(p);
System.out.println(value);
// 修改字段值
f.set(p, 50);
Student q=(Student)p;//p为Object型,强制转为Student型。
System.out.println(q.getScore()); // "Xiao Hong"
}
}

class Student extends Person{
public int score;
private int grade;
public Student(int score){
this.score=score;
}
int getScore(){
return score;
}
}
class Person{
public String name;
}

运行结果

1
2
3
4
5
public int Student.score
public java.lang.String Person.name
private int Student.grade
45
50

通过Field实例可以读取或设置某个对象的字段,如果存在访问限制,要首先调用setAccessible(true)来访问非public字段。

通过反射读写字段是一种非常规方法,它会破坏对象的封装。因此多用于底层设计。

调用对象的方法

java的反射API提供的 Method对象封装了方法的所有信息:

通过 Class实例的方法可以获取 Method实例:

  • Method getMethod(name, Class…):获取某个public的Method(包括父类)
  • Method getDeclaredMethod(name, Class…):获取当前类的某个Method(不包括父类)
  • Method[] getMethods():获取所有public的Method(包括父类)
  • Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)

通过 Method 实例可以获取方法信息:

  • getName():返回方法名称,例如:”getScore”;
  • getReturnType():返回方法返回值类型,也是一个Class实例,例如:String.class;
  • getParameterTypes():返回方法的参数类型,是一个Class数组,例如:{String.class, int.class};
  • getModifiers():返回方法的修饰符,它是一个int,不同的bit表示不同的含义。

通过 Method 实例可以调用某个对象的方法:Object invoke(Object instance, Object... parameters);

通过设置 setAccessible(true)来访问非public方法;

通过反射调用方法时,仍然遵循多态原则。

调用构造函数

通过Class实例获取Constructor的方法如下:

  • getConstructor(Class…):获取某个public的Constructor;
  • getDeclaredConstructor(Class…):获取某个Constructor;
  • getConstructors():获取所有public的Constructor;
  • getDeclaredConstructors():获取所有Constructor。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Main {
public static void main(String[] args) throws Exception {
// 获取构造方法Integer(int):
Constructor cons1 = Integer.class.getConstructor(int.class);
// 调用构造方法:
Integer n1 = (Integer) cons1.newInstance(123);
System.out.println(n1);

// 获取构造方法Integer(String)
Constructor cons2 = Integer.class.getConstructor(String.class);
Integer n2 = (Integer) cons2.newInstance("456");
System.out.println(n2);
}
}

获取继承关系

通过Class对象可以获取继承关系:

  • Class getSuperclass():获取父类类型;
  • Class[] getInterfaces():获取当前类实现的所有接口。

通过Class对象的isAssignableFrom()方法可以判断一个向上转型是否可以实现。

动态代理

Java标准库提供了动态代理功能,允许在运行期动态创建一个接口的实例;

动态代理是通过Proxy创建代理对象,然后将接口方法“代理”给InvocationHandler完成的。

参考

廖雪峰的Java教程——反射

评论

Gitalk评论系统对接至Github Issue,随心评论🐾🐾.....