反射

  1. 访问字段
  2. 调用方法
    1. 调用构造方法
  3. example

JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息(类名,包名,父类,接口,方法,字段等),因此只要获取了某个Class实例,就能通过这个实例获取对应的class的所有信息,这就是反射(Reflection)

获取一个class的Class实例的方法有

1
2
//直接通过class的静态变量class获取
Class clazz = String.class;
1
2
3
//通过实例变量的getClass()方法
String s = "n1ng"
Class clazz = s.getClass();
1
2
//如果知道Class的完整类名,可以通过静态方法Class.forName()获取
Class clazz = Class.forName("java.lang.String");

对于一个Object实例,只要获取了Class就可以知道他的所有信息

  • getSuperclass(),获取父类
  • getInterfaces(),获取接口

访问字段

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

调用方法

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

使用反射调用方法时,仍然遵循多态原则,会调用实际类型的覆写方法

调用构造方法

通过反射来创建实例时可以用newInstance()方法(Person p = new Person.class.newInstance();),但是他只能调用public无参数的构造方法,使用Constructor对象则可以避免。Constructor对象包含一个构造方法的所有信息,可以创建一个实例

  • getConstructor(class)获取某个public的Constructor
  • getDeclaredConstructor(class),获取某个Constructor
  • getConstructors(),获取所有public的Constructor
  • getDeclaredConstructors(),获取所有的Constructor
1
2
3
4
5
6
//对于非public的Constructor需要setAccessible(true)设置允许访问
Constructor con = Int.class.getConstructor(int.class);
Integer n = (Integer) con.newInstance(123)
Constructor con1 = Int.class.getConstructor(String.class);
Integer n1 = (Integer) con1.newInstance("123")

example

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public class Main {
public static void main(String[] args) {
printClassInfo("".getClass());
printClassInfo(Runnable.class);
printClassInfo(java.time.Month.class);
printClassInfo(String[].class);
printClassInfo(int.class);

//对于一个实例,我们可以先拿到该实例某个字段对应的Field,在获取这个实例的字段的值
Object p = new Person("n1ng");
Class clazz = p.getClass();//获取Class实例
Field f = clazz.getDeclaredField("name");//获取Feild实例
f.setAccessible(true);//name为private字段,需要设置为允许访问
Object value = f.get(p);//获取指定实例的指定字段的值
System.out.println(value);//"n1ng"
//也可以通过Field实例设置字段的值,通过Field.set(Object,Object),其中第一个参数是指定的实例,第二个参数是待修改的值
f.set(p,"n2ng");
System.out.println(p.getName());//"n2ng"

//获取到Method方法包括方法名(getName()),返回值类型(getReturnType()),参数类型(getParameterTypes()),返回方法的修饰符(getModifiers())
//获取public的方法getScore,参数为String
System.out.println(clazz.getMethod("getScore",String.class()));
//获取继承的public方法getName,没有参数
System.out.println(clazz.getMethod("getName"));
//获取private的方法getGrade(),参数为int
System.out.println(clazz.getDeclaredMethod("getGrade",int.class));

//通过反射来调用方法
String s = "Hello World"
Method m = String.class.getMethod("substring",int.class);
String r = (String) m.invoke(s,6);//使用invoke即调用该方法,第一个参数为调用的实例,后面的就是方法的参数
//调用静态方法parseInt,参数为String
Method m1 = Inter.class.getMethod("parseInt",String.class);
Integer n = (Integer) m1.invoke(null,"1111");
//调用非public方法,需要通过Method.setAccessible(true)设置允许调用
Person p = new Person();
Method m2 = p.getClass().getDeclaredMethod("setName",String.class);
m2.setAccessible(true);
m2.invoke(p,"n1ng");

}

static void printClassInfo(Class clazz) {
System.out.println("Class name: " + clazz.getName());
System.out.println("Simple name: " + clazz.getSimpleName());
if (clazz.getPackage() != null) {
System.out.println("Package name: " + clazz.getPackage().getName());
}
System.out.println("is interface: " + clazz.isInterface());
System.out.println("is enum: " + clazz.isEnum());
System.out.println("is array: " + clazz.isArray());
System.out.println("is primitive: " + clazz.isPrimitive());
}

static void printFieldInfo(Class clazz){
//getField方法获取了字段的所有信息,包括字段名称(getName()),字段类型(getType()),字段的修饰符(getModifiers())
System.out.println(clazz.getField("name"));//获取name字段
System.out.println(clazz.getDeclaredField("sex"))//获取private字段sex
}

class Person {
String name;
private void setName(String name) {
this.name = name;
}
}

}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 3049155267@qq.com

💰

×

Help us with donation