一、什么是反射
反射是指在程序运行时动态地获取类的信息,包括类名、字段、方法等。Java提供了一系列反射方法来操作(如获取、创建、修改、调用)Class对象、构造函数、方法、字段等。通过反射,我们可以创建对象、调用方法和访问字段,而不需要提前知道类的具体定义。同时反射也是一种实现动态加载的技术之一。
二、基于反射进行动态加载
贴一段用于辅助测试的代码:
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
| package com.example.uu; import com.test.wtf.Dog;
public class Test {
public String publicStr; private String privateStr = "abc";
Dog dog;
public Test(String publicStr) { this.publicStr = publicStr; this.dog = new Dog("ww"); }
public Test(){
}
public String getPublicStr() { return publicStr; }
public String getPublicStr(int a) { return publicStr; } }
|
基于上面这段代码, 来学习如何使用Java反射。
2.1 类反射
2.1.1 获取类
Class.forName(ClassName)
:动态加载类,ClassName
指定要加载的类名。
ClassLoader的loaderclass()
:动态加载类,ClassName
指定要加载的类名。
类名.class
:非动态加载。
类对象.getClass()
:非动态加载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Class cl = Class.forName("com.example.uu.Test");
Class cl = ClassLoader.getSystemClassLoader().loadClass("com.example.uu.Test");
Class sClass = String.class; System.out.println(sClass);
String a = "a"; Class aClass = a.getClass(); System.out.println(aClass);
|
2.1.2 通过类获取类实例
class.newInstrance()
:执行无参构造获取类实例,该方法要求class
类有无参构造方法。
示例代码
1 2 3 4
| Class cl = Class.forName("com.example.uu.Test");
Object o = cl.newInstance();
|
2.2 构造方法反射
2.2.1 获取构造方法
class.getConstructor(...ParameterTypes)
:获取class
类中的public权限的构造方法,ParameterTypes
指定所获取的构造方法中的参数的类型,没有则表示无参。
class.getConstructors()
:获取class
类中的所有public权限的构造方法。
class.getDeclaredConstructor(...ParameterTypes)
:获取class
类中的任意构造方法。
class.getDeclaredConstructors()
:获取class
类中的所有构造方法。
示例代码:
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
| Constructor constructor = cl.getConstructor(); System.out.println(constructor);
Constructor constructor = cl.getConstructor(String.class); System.out.println(constructor);
Constructor[] constructors = cl.getConstructors(); for (Constructor con:constructors) { System.out.println(con); System.out.println(con.getName() + "||" + con.getModifiers() + "||" + Arrays.toString(con.getParameters()) + "||" + Arrays.toString(con.getParameterTypes())); }
|
2.2.2 通过构造方法获取类实例
constructor.newInstance(...args)
:通过constructor
构造方法构造类实例对象,根据获取到的constructor
构造方法来决定是否需要传入参数args
。
constructor.setAccessible(bool)
:设置constructor
构造函数的访问权限,若bool
为true则表示取消构造函数的访问权限控制,这意味着private声明的构造函数也可以进行访问。
示例代码:
1 2 3 4 5 6 7 8 9
| Class cl = Class.forName("com.example.uu.Test"); Constructor constructor = cl.getConstructor(); Object o = constructor.newInstance();
Class cl= Class.forName("com.example.uu.Test"); Constructor constructor = cl.getConstructor(String.class); Object obj = constructor.newInstance("aaaaaaaaaaaaaaaa");
|
2.3 字段反射
2.3.1 获取字段
class.getField(FieldName)
:获取class
类中的带public声明的FieldName
变量。
class.getFields()
:获取class
类中的带public声明变量。
class.getDeclaredField(FieldName)
:获取class
类中的FieldName
变量。
class.getDeclaredFields()
:获取class
类中的所有变量。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Field field = cl.getField("publicStr"); System.out.println(field);
Field[] declaredFields = cl.getDeclaredFields(); for(Field dec : declaredFields){ System.out.println(dec); }
|
2.3.2 操作字段
field.getXxx(obj)
:获取obj
对象的field
字段的属性值。Xxx
代指8个基本数据类型,如果该属性类型是引用类型则直接使用Field.get(obj)
。
field.setXxx(obj, value)
:将obj
对象的Field字段赋值为value
。Xxx
代指8个基本数据类型,如果该字段类型是引用类型则直接使用Field.set(obj, value)
。
field.setAccessible(bool)
:设置field
字段的访问权限,若bool
为true则表示取消字段的访问权限控制,这意味着private声明的字段也可以进行访问。
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Class cl= Class.forName("com.example.uu.Test");
Constructor constructor = cl.getConstructor(String.class);
Object newtest = constructor.newInstance("ousasf");
Field privateStr = cl.getDeclaredField("privateStr");
privateStr.setAccessible(true); System.out.println(privateStr.get(newtest));
privateStr.set(newtest,"ahlsdfjpasp"); System.out.println(privateStr.get(newtest));
|
2.4 方法反射
2.4.1 获取方法
class.getMethod(MethodName,...ParameterTypes)
:获取class
类中的public权限的方法,MethodName
指定所要获取的方法的方法名,ParameterTypes
指定所获取的方法中的参数的类型,没有则表示无参。
class.getMethods()
:获取class
类中所有public权限的方法。
class.getDeclaredMethod(MethodName,...ParameterTypes)
:获取class
类中任意方法。
class.getDeclaredMethods()
:获取class
类的所有方法。
示例代码:
1 2 3
| Method method = cl.getMethod("getPublicStr",int.class); System.out.println(method);
|
2.4.2 执行方法
method.invoke(obj,...args)
:调用obj
对象的method
方法,args
指定传入的参数,没有则表示无参。
method.setAccessible(bool)
:设置method
方法的访问权限,若bool
为true则表示取消方法的访问权限控制,这意味着private声明的方法也可以被调用。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Class cl= Class.forName("com.example.uu.Test");
Constructor constructor = cl.getConstructor(String.class);
Object newtest = constructor.newInstance("abcdedfg");
Method method = cl.getDeclaredMethod("getPublicStr"); System.out.println(method);
System.out.println(method.invoke(newtest));
|
参考:
Java反射机制-十分钟搞懂 - 知乎 (zhihu.com)