0、反射技术
反射技术是Java生态中的重要内容,在Spring以及其他框架中得到了广泛的应用。
有了反射技术,我们可以在程序运行的过程中:
- 构建任意一个类的对象,
- 了解任意一个对象所属的类,
- 获悉任意一个类中的所有成员变量和方法,
- 调用任意一个类中的属性和方法。
1、获取方法
1.1、创建实体类
实体类中包含私有方法、公有方法、私有变量、公有变量。
代码语言:javascript复制public class Student {
private String name;
private Integer age;
public String className;
public Student() {
}
private Student(String name) {
this.name = name;
}
public Student(Integer age) {
this.age = age;
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
private void getAge(){
System.out.println("这是一个私有方法");
}
public void getName(){
System.out.println("这是一个公有方法");
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setClassName(String className) {
this.className = className;
}
}
1.1、获取构造方法
1.1.1 获取类中的所有构造方法
首先需要通过上一篇文章中提到的方法,获取到 class对象,再通过 getDeclaredConstructors()
获取到该类下所有构造方法。
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
Constructor<?>[] constructors = student.getDeclaredConstructors();
for (Constructor constructor : constructors){
System.out.println(constructor);
}
}
}
输出的结果如下:
public com.reflect.Student(java.lang.String,java.lang.Integer) public com.reflect.Student(java.lang.Integer) private com.reflect.Student(java.lang.String) public com.reflect.Student()
从输出的结果中,可以看到:实体类中四个构造方法都被获取到了,包括一个私有构造方法。及构造方法中的参数列表也能被取出来。
1.1.2 获取所有公有构造方法
不同于获取所有构造方法的反射方法,这里使用 getConstructors()
即可。
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
Constructor<?>[] constructors = student.getConstructors();
for (Constructor constructor : constructors){
System.out.println(constructor);
}
}
}
输出如下:
public com.reflect.Student(java.lang.String,java.lang.Integer) public com.reflect.Student(java.lang.Integer) public com.reflect.Student()
没有获取到类中类型为 private 的构造方法,仅有 public 方法。
1.1.3 根据参数列表,获取对应的构造方法
如果我们想要根据参数列表,获取到特定的构造方法时,可以使用 getDeclaredConstructor()
方法,方法中指明构造方法需要的参数:
- 所有参数,必须使用 class 对象;
- 参数的顺序应和构造方法中的顺序一致;
- 要获取无参构造方法,可以输入 null 作为参数,或为空;
- 这种方式可能会产生方法找不到的异常,因此需要对异常进行捕获或抛出。
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) {
try {
Class<Student> student = Student.class;
//获取私有构造方法
Constructor<?> constructor = student.getDeclaredConstructor(String.class);
System.out.println(constructor);
//获取公有构造方法
Constructor<?> constructor2 = student.getDeclaredConstructor(String.class, Integer.class);
System.out.println(constructor2);
//获取无参构造方法
Constructor<?> constructor3 = student.getDeclaredConstructor(null);
System.out.println(constructor3);
}catch (Exception e){
e.printStackTrace();
}
}
}
输出结果为
private com.reflect.Student(java.lang.String) public com.reflect.Student(java.lang.String,java.lang.Integer) public com.reflect.Student()
- 如果只想获取 public 类型的构造方法,可以使用
getConstructor()
方法,当对应的构造方法为 private 时,会报异常java.lang.NoSuchMethodException
; - 根据参数列表没有找到对应的方法,程序会报异常
java.lang.NoSuchMethodException
。
1.2、获取普通方法
1.2.1 获取所有普通方法
使用class对象的 getDeclaredMethods()
,可以获取当前类下所有普通方法(非构造方法)。
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
//获取所有方法
Method[] declaredMethods = student.getDeclaredMethods();
for (Method method : declaredMethods){
System.out.println(method);
}
}
}
输出结果为
public void com.reflect.Student.getName() public void com.reflect.Student.setName(java.lang.String) private void com.reflect.Student.getAge() public void com.reflect.Student.setAge(java.lang.Integer) public void com.reflect.Student.setClassName(java.lang.String)
类型为 private 和 public 的方法,都被获取到了。
1.2.2 获取所有公有的普通方法
使用class对象的 getMethods()
,可以获取当前类及其所有父类下所有被 public 修饰的普通方法(非构造方法)。
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
//获取所有方法
Method[] declaredMethods = student.getMethods();
for (Method method : declaredMethods){
System.out.println(method);
}
}
}
输出结果中,包含了 Student 类及默认父类 Object 类下所有由 public 修饰的方法。
public void com.reflect.Student.getName() public void com.reflect.Student.setName(java.lang.String) public void com.reflect.Student.setAge(java.lang.Integer) public void com.reflect.Student.setClassName(java.lang.String) public final void java.lang.Object.wait() throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public java.lang.String java.lang.Object.toString() public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll()
1.2.3 根据指定方法名及参数列表,获取指定方法
- 如果要获取的方法为 public 时,使用
getMethod()
方法; - 如果想要获取私有方法时,需要使用
getDeclaredMethod()
方法。 - 因为存在同名方法,需要在
getMethod()
方法中第一个参数指定要获取的方法名,后边为参数列表; - 无参方法时,参数列表可以没有,或使用 null 表示;
- 因为可能存在方法找不到的情况,所以这里需要对异常进行处理或抛出;
- 当使用
getMethod()
获取 private 修饰的方法时,也会抛出方法找不到的异常。
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
try {
//获取带参方法
Method method = student.getMethod("setAge", Integer.class);
System.out.println(method);
//获取无参方法
Method method2 = student.getMethod("getName", null);
System.out.println(method2);
//获取无参方法
Method method3 = student.getMethod("getName");
System.out.println(method3);
}catch (Exception e){
e.printStackTrace();
}
}
}
输出结果
public void com.reflect.Student.setAge(java.lang.Integer) public void com.reflect.Student.getName() public void com.reflect.Student.getName()
2、获取成员变量
获取所有成员变量
代码语言:javascript复制import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
Field[] declaredFields = student.getDeclaredFields();
for (Field field: declaredFields){
System.out.println(field);
}
}
}
输出结果
private java.lang.String com.reflect.Student.name private java.lang.Integer com.reflect.Student.age public java.lang.String com.reflect.Student.className
3、获取类的其他信息
3.1、获取类名
代码语言:javascript复制public class Test {
public static void main(String[] args) {
Class<Student> student = Student.class;
System.out.println(student.getName());
}
}
获取类名其实有多种方式:
要么是通过类名获取,
或者通过对象获取,
或者指定类的全路径获取。
3.2、获取包名
可以拿到该类所在的包的全路径信息。
代码语言:javascript复制public class Test {
public static void main(String[] args) {
Class<HighSchoolStudent> student = HighSchoolStudent.class;
Package aPackage = student.getPackage();
System.out.println(aPackage);
}
}
3.3、获取父类
代码语言:javascript复制public class Test {
public static void main(String[] args) {
Class<HighSchoolStudent> student = HighSchoolStudent.class;
Class<? super HighSchoolStudent> superclass = student.getSuperclass();
System.out.println(superclass);
}
}
这种方式只能拿到该类的直接父类,如果想要获取所有父类,可以在拿到父类后循环遍历,直到父类为 Object 为止。
代码语言:javascript复制public class Test {
public static void main(String[] args) {
Class<ArrayList> arrayListClass = ArrayList.class;
Class superclass = arrayListClass.getSuperclass();
System.out.println(superclass);
while (! "java.lang.Object".equals(superclass.getName())) {
superclass = superclass.getSuperclass();
System.out.println(superclass);
}
}
}
输出:
class java.util.AbstractList class java.util.AbstractCollection class java.lang.Object
3.4、获取实现的所有接口
该方法可以获取到该类实现的所有接口。
代码语言:javascript复制import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
Class<ArrayList> arrayListClass = ArrayList.class;
Class<?>[] interfaces = arrayListClass.getInterfaces();
for(Class clazz: interfaces){
System.out.println(clazz.getName());
}
}
}
输出如下:
java.util.List java.util.RandomAccess java.lang.Cloneable java.io.Serializable