Java反射学习
反射概念
• Java反射(Reflection)是一种新的操作类中成员变量、构造方法和普通方法的机制,为了实现对成员变量、构造方法和普通方法的操作,我们需要借助Java自身提供的java.lang包下的Class类和java.lang.reflect包下的反射API 。
单纯看这个概念可能比较抽象,我们从一般的情况说起:
普通的调用成员变量,构造方法、成员方法的 例子:
图中Test类里就是普通的调用成员变量,构造方法、成员方法的一种方式。而今天要学习的反射,就是调用成员变量、成员方法、构造方法的另一种方式。
Class类
要学习反射,就要先学习Class类。我们知道,类是一组对象抽取出来相同的属性和方法,而Class类相当于把不同的类中相同的属性和方法抽取出来,形成类的类。
概念理解
• Class类是Java 反射机制的入口,封装了一个类或接口的运行时信息,通过调用Class类的方法可以获取这些信息。
查看Class类的源码:
从源码中,我们可以读出一些信息:
- Class类由final修饰,意味着该类不可以被子类继承。
- 该类实现了Serializable接口;
- 该类的构造方法被private所修饰,即不能通过new关键字创建该类的对象,即如下的创建对象方式不可行:
获取不同的Class类
- 获取某一个自定义类对应的Class类实例化对象的三种方法:
package test;
import vo.Student;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
//方法一
Class studentClass = Student.class;
System.out.println("1、"+studentClass);
//方法二
studentClass = Class.forName("vo.Student");
System.out.println("2、"+studentClass);
//方法三
studentClass = new Student().getClass();
System.out.println("3、"+studentClass);
}
}
运行后输出;
其中的StudentClass代表的就是Student这个类。
- 获取数组类型的Class类:
package test;
import vo.Student;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
String [] names = {};
Class arrayClass = String[].class;
System.out.println(arrayClass);
}
}
输出:
- 获取基本类型数据的Class类:
通过包装类.TYPE获取Class类实例,当然,也可以通过基本数据类型.class获取Class类实例。
这里通过int(Integer)来举例说明
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class intClass = Integer.TYPE;
System.out.println("1、"+intClass);
intClass = Integer.class;
System.out.println("2、"+intClass);
}
}
运行后输出结果:
通过结果我们可以看出:
第一种方式获取到的是基本数据类型int
第二种方式获取到的是Integer这个类
- 获取父类Class:
使用getSuperclass()方法
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class fatherClass = Student.class.getSuperclass();
System.out.println(fatherClass);
}
}
运行输出结果:
因为Student类的父类是Object类,所以输出为:
另一个更直观的例子:
输出结果为:
构造方法相关
1.获取构造方法
- 获取public级别的构造方法
使用Class类中的 getConstructors()方法,返回一个Constructor类型的数组。注意看控制台输出的构造方法的参数类型。第三个构造方法由于访问权限为private,所以没有输出。 - 获取所有的构造方法
使用Class类的getDeclaredConstructors()方法,返回一个Constructor类型的数组。
Student类:
package vo;
public class Student {
public Student() {
System.out.println("无参构造方法");
}
public Student(int age) {
System.out.println("有参构造方法1");
}
private Student(String name) {
System.out.println("有参构造方法2");
}
}
Test类:
package test;
import java.lang.reflect.Constructor;
import vo.Student;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
//获取到对应的类
Class studentClass = Student.class;
//获取到一个类中所有public级别的构造方法
Constructor [] constructors = studentClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("-------------------------------------");
//忽略访问权限,获取到一个类中所有构造方法
constructors = studentClass.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
}
}
- 根据参数不同获取不同的构造方法
注意参数要写为基本数据类型.TYPE或类.class
注意: 这里将Student类的方法访问权限都改成了pulic级别,如果是访问级别为private,则要将方法改为getDeclaredConstructor().如下图所示,其中也包括了getConstructor()方法访问私有成员方法报错的情况。
Test类:
package test;
import java.lang.reflect.Constructor;
import vo.Student;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
//获取到对应的类
Class<Student> studentClass = Student.class;
Constructor<Student> constructor0 = studentClass.getDeclaredConstructor();
System.out.println(constructor0);
System.out.println("-------------------------------");
Constructor<Student> constructor1 = studentClass.getDeclaredConstructor(Integer.TYPE);
System.out.println(constructor1);
System.out.println("*******************************");
//这个方法没有改成getDeclaredConstructor,因为无法找到第2个有参构造方法所以报错
Constructor<Student> constructor2 = studentClass.getConstructor(Integer.TYPE,String.class);
System.out.println(constructor2);
}
}
2.查看类的构造方法信息
- 查看属于哪个类:
使用Constructor类的getDeclaringClass()方法,然后用getName()获取。
- 获取构造方法名
使用getName()方法
- 获取修饰符
- 注意getModifiers()方法的返回值是int类型
源代码:
package test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import vo.Student;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
//获取到对应的类
Class<Student> studentClass = Student.class;
//获取到一个构造方法
Constructor<Student> constructor = studentClass.getDeclaredConstructor();
//构造方法属于哪一个类
String ClassName = constructor.getDeclaringClass().getName();
System.out.println(ClassName);
//获取构造方法名
String constructorName = constructor.getName();
System.out.println(constructorName);
//获取构造方法修饰符
int result = constructor.getModifiers();
String m = Modifier.toString(result);
System.out.println(m);
}
}
- 查看参数列表
使用getParameterTypes()方法
3.反射调用构造方法
- 调用public级别的构造方法
使用Constructor类的newInstance(…)方法,括号内为对应的参数。使用不同的参数列表来找到相应的构造方法。
如代码:
Object obj = constructor.newInstance(12,"Tom");
如上图,创建的obj相当于一个Student对象(属于上转型对象)。根据参数执行了有参构造方法2。
注意出现异常后都抛出
- 调用private级别的构造方法
在调用前使用setAccessible()方法:
代码:
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//获取到对应的类
Class studentClass = Student.class;
//获取到构造方法
Constructor<Student> constructor = studentClass.getDeclaredConstructor(Integer.TYPE);
Constructor<Student> constructor1 = studentClass.getDeclaredConstructor(Integer.TYPE,String.class);
//调用构造方法
Object obj = constructor.newInstance(12);
//忽略访问权限
constructor1.setAccessible(true);
Object obj1 = constructor1.newInstance(12,"Tom");
}
}