复习重点
- 反射基本概念
- 获取class文件对象的三种方式
- 利用反射技术获取类中的成员变量、成员方法、构造方法,并实例化对象的简易方式
- 案例
目录
1.反射基本概念
- 类加载到内存时,将类的各个组成部分封装成其他对象,这就是反射。
2.获取class文件对象的三种方式
- Object.getClass()——引用类型的对象的获取方式。
- 类的class属性——无对象的获取方式 。注意:java为每种数据类型(基本数据类型4类8种,引用数据类型(数组,类,接口))都赋予了一个class属性
- 类的forName(“全类名”)——类的完整路径。
Person p = new Person();
Class clazz1 = p.getClass();
Class clazz2 = Person.class;
Class clazz3 = Class.forName("com.itheima.demo02reflect.Person");
3.反射技术
- 获取构造方法
getConstructors() 获取类中所有公共构造方法
getDeclaredConstructors() 获取类中所有构造方法(包括公共、保护、默认(包)访问和私有)
getConstructor(Class<?>... parameterTypes) 获取类的指定公共构造方法
getDeclaredConstructor(Class<?>... parameterTypes) 获取类或接口的指定构造方法(包括公共、保护、默认(包)访问和私有)
Constructor con1 = clazz.getConstructor();
Constructor con2 = clazz.getConstructor(String.class, int.class, String.class)
Constructor con3 = clazz.getDeclaredConstructor(String.class, int.class);//获取私有构造方法
Constructor[] cons = clazz.getConstructors();
- 实例化对象
使用newInstance()空参构造方法创建对象
Class clazz = Class.forName("com.itheima.demo03reflect.Person");
Object obj = clazz.newInstance();
Person p = (Person)obj;
p.setName("张三");
p.setAge(40);
p.setSex("男");
- 获取成员方法并运行
Method[] getMethods() 获取类中所有的公共成员方法,包含继承自父类和实现自接口的
Method[] getDeclaredMethods() 获取类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
Method getMethod(String name, Class<?>... parameterTypes) 获取指定公共成员方法
Method getDeclaredMethod(String name, Class<?>... parameterTypes) 获取类或接口的指定已声明方法(公共、保护、默认(包)访问和私有)
String getName() 以 String 形式返回此 Method 对象表示的方法名称。
Object invoke(Object obj, Object... args) 运行获取到的成员方法
Method.setAccessible(true) 解决:暴力反射 取消java的语言访问检查
//已经有clazz文件对象,obj实例化对象
Method getNameMethod = clazz.getMethod("getName");//获取指定公共方法
Method setNameMethod = clazz.getMethod("setName", String.class);//指定方法的参数也要写
//获取所有公有的包括继承自Object类的很多方法
Method[] methods = clazz.getMethods();
for (Method m : methods) {
System.out.println(m.getName());
}
//会获取到所有方法,但没有继承的方法,一般用这个,或者指定方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
System.out.println(m.getName());
}
//获取私有方法show()要执行该方法,使用暴力反射
Method show = clazz.getDeclaredMethod("show");//show是私人方法不能直接使用
show.setAccessible(true);
show.invoke(obj);
- 获取实现的接口
Class<?>[] getInterfaces() 确定此对象所表示的类或接口实现的接口。
- 获取成员属性
getField(String)获取指定公共属性,getFields()获取所有公共属性
4.案例
需求:实现一个“框架”类,即测试其他类的一个类,在不改变任何代码的前提下,可以创建任意对象,并执行任意方法(在配置文件中可以定义任何全类名或者方法)。
实现:1.配置文件(使用properties集合配置文件,使用方法见基础班day11笔记)
2.反射(将javac编译后的.class文件加载进内存的同时,并将类中定义的成员变量、构造函数、成员方法,分别封装为 Field、Constructor、Method对象,即将类的各个组成部分封装成各个对象,就称为反射机制)
步骤:
1:将需要创建的对象的全类名和需要执行的方法名称定义在配置文件中。
2:在反射测试类中加载读取(load方法)配置文件
3:使用反射技术加载类文件进内存(Class.forName(全类名))
4:创建对象(newInstance)
5:执行方法(invoke)
测试类ReflectTest
package csdn.reflect.demo01;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class ReflectTest {
public static void main(String[] args) throws Exception {
//将需要创建的对象的全类名和需要执行的方法名称定义在配置文件中。
Properties pro = new Properties();
/*在反射测试类中加载读取配置文件,一般使用Class读取一个文件时,都会使用类加载器的getResourceAsStream(文件名)方法
获取指定文件的内容,方法返回的是一个InputStream流,也就是将文件转换成流,便于读写,properties集合是一个和IO流
相结合的集合,之后再使用properties集合的load方法,将流文件中的内容加载到集合中,*/
/*注意:配置文件虽然命名为properties,但是和Properties集合不一样,那是将文件中的内容load进集合中,
或者把集合中内容store进文件中,文件就是文件,集合就是集合!*/
//获取当前ReflectTest类的class文件对象
Class reflectClazz = ReflectTest.class;
//获取该类的类加载器
ClassLoader classLoader = reflectClazz.getClassLoader();
//使用类加载器的getResourceAsStream(文件名)方法,获取指定流文件
InputStream rs = classLoader.getResourceAsStream("pro.properties");
//使用load方法将流文件中的内容加载到集合中
pro.load(rs);
//使用集合的getProperty的方法获取加载进集合中的内容
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//使用反射技术加载类文件进内存(Class.forName(全类名)),同时可以获取该类的文件对象。
// 此时可以加载任何我想测试的类,比如我想测试的是随便写的Student类
Class clazz = Class.forName(className);
//实例化Class文件对象(newInstance),clazz.getConstructor().newInstance()=clazz.newInstance()
Object obj = clazz.newInstance();
//获取该类的指定名称的方法对象,执行方法(invoke)
Method method = clazz.getMethod(methodName);
method.invoke(obj);
}
}
被测试的Student类
package csdn.reflect.demo01;
public class Student {
public Student() {
}
public void show() {
System.out.println("我在黑马学反射");
}
}
pro.properties文件
className=csdn.reflect.demo01.Student
methodName=show
注意:配置文件在放在src下就没问题了,和其他类放在一个包中,出现了问题!