1.1 什么是反射
程序运行期间,使用另外一种技术来创建对象实例,调用方法,后期我们经常使用,但很少去写【框架】
1.2 字节码对象
获取字节码对象
// 对象实例.getClass()
// 类.class
// Class.forName("全限定类名")
代码片段
// Class.forName("全限定类名");
@Test
public void test03() throws Exception {
Class c1 = Class.forName("com.itheima.b_reflect.b1_class.Student");
System.out.println(c1);
}
常用方法
public String getSimpleName(); 获取字节码简单名称 类名
public String getName(); 获取字节码全限定类名 包名+类名
public T newInstance(); 创建对象实例 要求:空参构造方法
代码片段
@Test
public void test03() throws Exception {
// 创建Student对象实例
Student o = (Student) clazz.newInstance();
System.out.println(o);
}
1.3 构造器
通过字节码对象获取构造器
public Constructor[] getConstructors(); 获取所有public修饰的构造器
public Constructor [] getDeclaredConstructors(); 获取所有声明的构造器
public Constructor getConstructor(Class.. 类型列表); 获取指定public修饰的构造器
public Constructor getDeclaredConstructor(Class.. 类型列表); 获取指定声明的构造器
常用方法
public T newInstance(Object... 参数列表); 创建对象实例
public void setAccessible(boolean true); 暴力反射
代码片段
// 获取private修饰的二个参数构造器
@Test
public void test05() throws Exception {
// 字节码对象
Class clazz = Class.forName("com.itheima.b_reflect.b2_constructor.Student");
// 构造器
// 错误 java.lang.NoSuchMethodException
// Constructor constructor = clazz.getConstructor(int.class, String.class);
Constructor constructor = clazz.getDeclaredConstructor(int.class, String.class);
// java.lang.IllegalAccessException
constructor.setAccessible(true); // 取消全限检查 (暴力反射)
// 创建对象实例
Object o = constructor.newInstance(3, "林允");
System.out.println(o);
}
1.4 方法
通过字节码对象获取方法
public Method[] getMethods(); 获取所有public修饰的方法,包括父类的
public Method[] getDeclaredMethods();获取所有声明的方法,不包括父类
public Method getMethod(String 方法名,Class... 类型列表); 获取指定public修饰的方法
public Method getDeclaredMethod(String 方法名,Class... 类型列表); 获取指定声明的方法
常用方法
public T invoke(Object 对象实例,Object... 参数列表); 调用对象实例方法
public void setAccessible(boolean true); 取消全限检查(暴力反射)
代码片段
// private修饰的 sleep方法 有返回值
@Test
public void test05() throws Exception {
// 字节码对象
Class clazz = Class.forName("com.itheima.b_reflect.b3_method.Student");
// 方法
// 错误 java.lang.NoSuchMethodException
// Method method = clazz.getMethod("sleep");
Method method = clazz.getDeclaredMethod("sleep");
// 创建对象实例
Object o = clazz.newInstance();
// java.lang.IllegalAccessException
method.setAccessible(true);// 取消全限检查 (暴力反射)
// 调用
Object result = method.invoke(o);
System.out.println(result);
}
// public修饰的 静态 study 方法
@Test
public void test06() throws Exception {
// 字节码对象
Class clazz = Class.forName("com.itheima.b_reflect.b3_method.Student");
// 方法
Method method = clazz.getMethod("study");
// 调用方法
method.invoke(null);
}
1.5 属性【字段】
因为我们定义的属性,都提供了 setXxx getXxx 方法
通过字节码对象获取字段
public Field[] getFields(); 获取所有public修饰的字段
public Field[] getDeclaredFields(); 获取所有声明的字段
public Field getField(String 字段名); 获取指定public修饰字段
public Field getDeclaredField(String 字段名); 获取指定声明的字段
常用方法
public void set(Object 对象实例,Object 实参内容); 对象实例赋值
setInt setDouble
public T get(Object 对象实例); 对象实例取值
getInt getDouble
public Class getType(); 当前字段的类型
public void setAccessible(boolean true); 暴力反射
代码片段
// 给 name字段 赋值 取值 并判类型
@Test
public void test() throws Exception {
// 字节码对象
Class clazz = Class.forName("com.itheima.b_reflect.b4_field.Student");
// 获取name字段
// Field field = clazz.getField("name");
Field field = clazz.getDeclaredField("name");
// 创建对象实例
Object o = clazz.newInstance();
// 暴力反射
field.setAccessible(true);
// 赋值
field.set(o, "舒淇");
// 取值
field.get(o);
System.out.println(o);
// 字段类型
Class<?> type = field.getType();
System.out.println(type);
}
1.6 反射案例
spring 容器 (创建对象实例、存储对象实例)
需求
编写一个工厂方法,根据配置文件的信息生产任意对象实例
需求分析
编写一个Student类(编号、姓名、性别) 编写一个配置文件(类的信息 全限定类名 属性和对应的值)编写一个工厂方法 加载配置文件 生产对象
步骤分析
1 编写一个Student类(编号、姓名、性别)
2 编写一个配置文件(类的信息 全限定类名 属性和对应的值)
3 编写一个工厂方法 加载配置文件 生产对象
// 读取配置文件信息
// 创建字节码对象
// 创建对象实例
// 根据其他的属性信息 给对象实例赋值
@Test
public void test() throws Exception {
// 创建properties对象
Properties pro = new Properties();
// 加载
pro.load(new FileReader("student.properties"));
// 获取配置文件的信息
String className = pro.getProperty("className");
String id = pro.getProperty("id");
String name = pro.getProperty("name");
String gender = pro.getProperty("gender");
// 创建字节码对象
Class clazz = Class.forName(className);
// 获取public类型的带参构造方法
Constructor constructor = clazz.getConstructor(int.class, String.class, String.class);
// 创建对象实例,赋值
Object o = constructor.newInstance(Integer.parseInt(id), name, gender);
System.out.println(o);
// 方法二
// 读取配置文件信息
InputStream is = TestRef.class.getClassLoader().getResourceAsStream("fun/chenqi/day01/demo01/student.properties");
Properties properties = new Properties();
properties.load(is);
// 创建字节码对象
Class clazz = Class.forName(properties.getProperty("className"));
// 创建对象实例
Object o = clazz.newInstance();
// 根据其他的属性信息 给对象实例赋值
Set<String> keys = properties.stringPropertyNames();
// 遍历key
for (String key : keys) {
// 处理 className 跳出本次循环
if ("className".equalsIgnoreCase(key)) continue;
// 获取 value
String value = properties.getProperty(key);
// 获取field id name gender
Field field = clazz.getDeclaredField(key);
field.setAccessible(true);// 暴力反射
// 获取当前的字段类型
Class<?> type = field.getType();
if (type == int.class) {
field.setInt(o, Integer.parseInt(value));
} else {
// 赋值操作
field.set(o, value);
}
}
System.out.println(o);