19.1 反射介绍 Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法 对于任意一个对象,都能够调用它的任意一个方法 这种动态获取的以及动态调用对象的方法的功能称为java语言的反射机制 (我理解为就是在运行时,可以去获取当前项目中的所有的.class文件,然后去使用它的方法) 就是在运行时主动的获取对象 19.1.1获取字节码文件的三种方法准备类:
[Java] 纯文本查看 复制代码 public class FuLei {
private String name;
public int age;
private String gender;
public FuLei() {}
private void ss(int a){
System.out.println(a);
}
public FuLei(String name, int age, String gender) {
super();
this.name = name;
this.age = age;
this.gender = gender;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "FuLei [name=" + name + ", age=" + age + ", gender=" + gender + "]";
}
public void method(){
System.out.println("我是父类的方法");
}
}
1、通过 对象名.getClass()方法获取 FuLei f = new FuLei(); Class<? extends FuLei> class1 = f.getClass(); 2、通过 类名.class属性来获取 System.out.println(FuLei.class); 3、通过 Class.forName(类的全名) ------类的全名是 包名.类名 Class<?> forName = Class.forName("com.test01.FuLei");//为了防止传入错误的类名此处将会抛出异常 ClassNotFoundException 19.1.2 通过获取的构造创建对象字节码对象是什么?如何获取? newInstance()新实例化对象方法,使用时一定要和获取构造器时的参数保持一致 getConstructor()方法返回的是一个字节码对象,之后的获取方法和属性的方法都是返回的相应的对象 //关于字节码对象,什么是字节码对象?如何获取? //首先要获取字节码 //这里利用第一种方式获取了字节码文件 Class<?> forName = Class.forName("com.test01.FuLei"); //获取了无参构造,方法一,通过forName.getConstructor()得到无参构造的对象,然后调用无参构造的对象来调用newInstance()方法 // Constructor<?> constructor = forName.getConstructor(); // Object newInstance1 = constructor.newInstance(); //方法二、根据无参构造进行实例化对象 newInstance()新实例化对象,只能创建无参构造来创建对象 Object newInstance = forName.newInstance(); System.out.println(newInstance); //根据有参构造进行实例化对象 Constructor<?> constructor2 = forName.getConstructor(String.class,int.class);//参数是传的类型的字节码文件 Object newInstance2 = constructor2.newInstance("刘欣明",25); System.out.println(newInstance2); 19.1.3 反射操作公共成员变量19.1.3.1反射public成员变量注意:这里只能获取被public修饰的成员 通过反射运行public变量流程 1. 通过反射获取该类的字节码对象 Class clazz = Class.forName("com.heima.Person"); 2. 创建该类对象 Object p = clazz.newInstance(); 3. 获取该类中需要操作的字段(成员变量) getField(String name) --> 方法传入字段的名称. 注意: 此方法只能获取公共的字段 Field f = clazz.getField("age"); 4. 通过字段对象中的方法修改属性值 void set(Object obj, Object value) --> 参数1): 要修改那个对象中的字段, 参数2): 将字段修改为什么值. f.set(p, 23); 代码演示: Class<?> forName = Class.forName("com.test01.FuLei"); Object fu = forName.newInstance(); Field age = forName.getField("age"); Field name = forName.getField("name"); name.set(fu, "刘欣明"); age.set(fu, 25); System.out.println(age);//public int com.test01.FuLei.age System.out.println(fu);//FuLei [name=刘欣明 Object age2 = age.get(fu); Object name2 = name.get(fu); System.out.println(age2);//25 System.out.println(name2);//刘欣明 方法总结: 通过反射获取成员变量并使用
Field[] getFields() --> 返回该类所有(公共)的字段
Field getField(String name) --> 返回指定名称字段
Field[] getDeclaredFields() --> 暴力反射获取所有字段(包括私有)
Field getDeclaredField(String name) --> 暴力反射获取指定名称字段
Field:
Object get(Object obj) --> Field对象调用, 返回传入对象的具体字段
void set(Object obj, Object value) --> Field对象调用
参数1: 要修改的对象
参数2: 将此对象的字段修改为什么值. 19.1.3.2反射private成员变量 反射private属性执行流程 1. 获取学生类字节码对象
2. 获取学生对象
3. 通过getDeclaredField方法获取私有字段
4. 通过setAccessible让jvm不检查权限
5. 通过set方法设置对象为具体的值 Class<?> forName = Class.forName("com.test01.FuLei");//获取字节码文件 Object fu = forName.newInstance();//获取实例对象 Field gender = forName.getDeclaredField("gender");//获取私有的成员变量 gender.setAccessible(true);//暴力反射 gender.set(fu, "男");//设置值 System.out.println(fu);//FuLei [name=null, age=0, gender=男 System.out.println(gender);//private java.lang.String com.test01.FuLei.gender Object xin = gender.get(fu); System.out.println(xin);//男 19.1.3.3 反射获取方法执行流程反射public方法执行流程 1. 获取学生类字节码对象
2. 反射手段创建学生对象
3. 调用getMethod方法获取Method对象, 方法形参接受方法的名字
4. 调用Method方法中的invoke()将方法运行 Class<?> Fu = Class.forName("com.test01.FuLei");//字节码文件 Object f = Fu.newInstance();//实例化对象 //无参无返回值 Method method = Fu.getMethod("method"); method.invoke(f);//调用方法 //有参无返回值的方法 Method method2 = Fu.getMethod("setName", String.class); method2.invoke(f, "lxm");//调用方法 System.out.println(f); 19.2 JavaBean/* * JavaBean:用于封装数据 * 类使用公共进行修饰 * 提供私有修饰的成员变量 * 为成员变量提供公共getter和setter方法 * 提供公共无参的构造 * 实现序列号接口 * */ 19.3BeanUtils的常用方法static void setProperty(Object bean, String name, Object value)
static String getProperty(Object bean, String name)
static void populate(Object bean, Map properties) setProperty 用来给对象中的属性赋值(了解) 参数1: 需要设置属性的对象 参数2: 需要修改的属性名称 参数3: 需要修改的具体元素 getProperty 用来获取对象中的属性(了解) 参数1: 要获取的javaBean对象 参数2: 对象中的哪个属性 Populate 用来给对象中的属性赋值(掌握) 参数1: 要设置属性的对象 参数2: 将属性以Map集合的形式传入 Key : 属性的名称 Value: 属性具体的值 BeanUtils 的setProperty和getProperty方法的底层并不是直接操作成员变量,而是操作成员变量有关的set和get方法 BeanUtils populate(javabean类,map); //方法setProperty() public static void setProperty(Object bean, String name,Object value) throws ReflectiveOperationException{ //通过反射获取字节码 Class clazz = bean.getClass(); //获取相应的属性对象 Field f = clazz.getDeclaredField(name); //设置权限 f.setAccessible(true); //赋值 f.set(bean, value); } //方法getProperty() public static String getProperty(Object bean, String name) throws ReflectiveOperationException{ //获取字节码对象 Class clazz = bean.getClass(); //获取属性的对象 Field f = clazz.getDeclaredField(name); f.setAccessible(true); Object obj = f.get(bean); return obj.toString(); } //方法 populate() public static void populate(Object bean,Map map) throws ReflectiveOperationException{ //根据map里面的键值对的key来获取bean类中的属性,没有属性的话 Class<? extends Object> c = bean.getClass(); Set keys = map.keySet(); for (Object key : keys) { try{ //根据key获取value Object value = map.get(key); //得到属性的对象 Field f = c.getDeclaredField(key.toString()); //设置权限 f.setAccessible(true); //赋值 f.set(bean, value); }catch(NoSuchFieldException e){ e.printStackTrace(); } }
|