一.什么是反射
在了解反射之前我们需要先简单来了解一下类加载的过程
-
在类加载的过程中,第一步JVM(JAVA虚拟机)将A.class文件读入内存方法区,第二步JVM为A.class创建唯一的Class类的对象,而Class对象是后面访问方法区对应数据的入口
-
在之前的学习的中,我们通常会用到class关键字,但这里说的Class非彼class,Class在java中是个实际存在的类型,而Class是后面反射需要经常用到的一个类型
-
前面提到在类加载的过程中,会将所有类型生成对应的Class对象,那么反射的应用之一就是可以通过Class来生成任意类的对象
-
准确来说:
在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一 个方法;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制
-
反射的核心API
-
java.long包
Class类:反射的核心类,可获取类的属性,方法等信息,生成类的实例 -
java.lang.reflect包
Field类 : 表示类的成员变量,可用来获取和设置类的属性值
Method类 : 表示类的方法,可用来获取类中的方法信息或者执行方法
Constructor类 : 表示类的构造方法
二.生成Class对象的三种方式
- 第一种Class.forName(包名.类型名)//更常用的一种方法,在编译期未知类型,更能体现反射的作用
//第一种方式Class.forName
//通过类型包名+类型名来获得需要生成的类型对象,示例生成的是work包下的Student类
//在反射过程中,有可能会出现一些异常所有需要捕捉一下异常
Class c1 =Class.forName("work.Student");
- 第二种调用对象实例方法getClass()
Student student1=new Student();//先创建类型对象
Class c2= student.getClass();//通过类型对象.getClass()方法来获取Class类型对象
- 第三种 类型.class
Class c3 = Student.class;//通过类型.class来获取Class对象
三.获取相关类的信息
获取属性
- getFields() - 获取所有可访问的公共字段
- getDeclaredFields - 所有字段
- getField(String name) - 返回一个特定的公共字段对象
- 代码示例
//第一步获得Class对象
Class studentClass = Class.forName("work.Student");//通过类型位置+类型名来获得Class对象
//获取Student类型的相关属性
Field[] fields = studentClass.getFields();//所有公共字段属性
Field[] fields1=studentClass.getDeclaredFields();//所有字段
Field bbb = studentClass.getField("bbb");//获取特定公共字段对象
//通过增强for来遍历输出所有属性名
System.out.println("***********所有公共字段************");
for (Field field : fields) {
System.out.println(field.getName());
}
System.out.println("************所有字段**************");
for (Field field : fields1) {
System.out.println(field.getName());
}
System.out.println("************特点字段**************");
System.out.println(bbb.getName());
获取方法
- getMethods() - 所有的公共方法,包括从超类和超接口继承的声明
- getDeclaredMethods() - 仅包含本类的所有方法,不包含继承/接口等方法
- getMethod(String name,Class[] parameterTypes) - 返回一个特点的方法对象
//第一步获得Class对象
Class studentClass = Class.forName("work.Student");//通过类型位置+类型名来获得Class对象
//获取Student类型的相关方法
Method[] methods = studentClass.getMethods();//所有的公共方法,包括从超类和超接口继承的声明
Method[] declaredMethods = studentClass.getDeclaredMethods();//所有方法,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法
Method ddd = studentClass.getMethod("ddd",null);//返回一个特点的方法对象,第一个参数:方法名,第二个参数:方法中的参数类型,无参即为null
//通过增强for来遍历输出所有方法名
System.out.println("***********所有公共字段************");
for (Method method : methods) {
System.out.println(method.getName());
}
System.out.println("************所有字段**************");
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName());
}
System.out.println("************bbb**************");
System.out.println(ddd.getName());
四.反射生成类的实例
需要用到的方法
- getConstructor()//获得相应类型的构造方法,返回的是Constructor类型对象
- newInstance()//通过构造方法对象完成类的实例化
代码示例(实例化无参对象)
//第一步获得Class对象
Class studentClass = Class.forName("work.Student");
//第二步获得相应类型的构造方法
Constructor constructor = studentClass.getConstructor();
//第三步根据构造方法对象完成类的实例化
Object o = constructor.newInstance();
代码示例(实例化有参对象)
//第一步获得Class对象
Class studentClass = Class.forName("work.Student");//通过类型位置+类型名来获得Class对象
//第二步获得相应类型的构造方法并设定参数类型
Constructor constructor=studentClass.getConstructor(int.class,String.class,double.class);
//第三步根据构造方法对象传入参数完成类的实例化
Object o = constructor.newInstance(1,"1",1.0);
五.属性的赋值与方法的调用
属性的赋值
//第一步获得Class对象
Class studentClass = Class.forName("work.Student");//通过类型位置+类型名来获得Class对象
//第二步获得相应类型的构造方法并设定参数类型
Constructor constructor=studentClass.getConstructor(int.class,String.class,double.class);
//第三步根据构造方法对象传入参数完成类的实例化
Object o = constructor.newInstance(1,"1",1.0);
//第四步获得指定属性返回Field类型的对象
Field aaa = studentClass.getField("aaa");
//第五步将实例化的对象o中的属性aaa赋值为888
aaa.set(o,888);
方法的调用
//第一步获得Class对象
Class studentClass = Class.forName("work.Student");
//第二步获得相应类型的构造方法并设定参数类型
Constructor constructor=studentClass.getConstructor(int.class,String.class,double.class);
//第三步根据构造方法对象传入参数完成类的实例化
Object o = constructor.newInstance(1,"1",1.0);
//第四步获得指定方法并返回Method类型的对象
Method ddd = studentClass.getMethod("ddd", null);
//第五步调用invoke方法来操作对象o中的ddd方法,null表示方法无参
ddd.invoke(o,null);