1、为什么要有反射
程序的运行分为编译器、运行期,正常情况下程序的代码都是在编译器就已经加载到jvm了,但是理工反射我们可以在运行期根据实际运行过程中的条件再决定把哪一个类的代码加载到内存中,进行运行,这一特性极大的提高了程序编写的灵活性。
2、JVM中类的加载(补充)
3、反射的结构图与class文件的组成
个人通俗理解:Executable的英文意思是可执行的,他作为一一个抽象类存在,用来约束所有方法(普通方法、构造函数方法)的实现,方法有属于类的一部分所以他又受Member接口的约束,而AccessibleObject是对可访问性的一个控制,作为方法的自然也受他的约束,故有实现了AccessibleObject接口。Field于此同理
4、Class对象获取获取的几种方式
获取class的方式有三种:.class、getClass()、forName(),不管通过怎样方式获得的class对象,他们获取到的都是相同的,这是因为每个类只有一个class文件
Persion persion1 = new Persion();
//运行期加载,获取class的三种方式
Class persionClass1 = Persion.class;
Class persionClass2 = persion1.getClass();
Class persionClass3 = Class.forName("com.reflect.Persion");
class相等性的验证(两个语句的输出结果均为true) :
//检验class是否相等
System.out.println(persionClass1==persionClass3);
System.out.println(persionClass1==persionClass2);
4、生成对象的步骤
5、Field、Constructor获取过程中的一些技巧
Field 的获取有两种方法:getDeclaredField、getField,这使用的过程中通常使用getDeclaredField(),同时使用setAccessible打开访问权限,否则会报错:
getDeclaredField:可以获取所有限定修饰符修饰的字段,但是不能够获取从父类继承来的
getField:只可以获取public修饰的字段,以及从父类继承过来的
访问修饰符的权限范围补充:
访问修饰符 | 内部类 | 包 | 子类 | 外部包 |
---|---|---|---|---|
public | 可见 | 可见 | 可见 | 可见 |
protected | 可见 | 可见 | 可见 | 不可见 |
default | 可见 | 可见 | 不可见 | 不可见 |
private | 可见 | 不可见 | 不可见 | 不可见 |
通过getField也只能访问到public修饰的父类方法:
Persion persion = new Persion("LiuMenglei",true,23);
Class persionClass = Persion.class;
//java.lang.NoSuchFieldException: fatherName
Field nameField = persionClass.getDeclaredField("fatherName");
System.out.println(nameField.get(persion));
//public修饰的父类属性,可以正常访问
Field fatherNameField = persionClass.getField("fatherName");
System.out.println(fatherNameField.get(persion));
//protected修饰的父类属性——java.lang.NoSuchFieldException: address
Field fatherAddressField = persionClass.getField("address");
fatherAddressField.setAccessible(true);
System.out.println(fatherAddressField.get(persion));
通过反射获取构造函数的方法也有多种——有参、无参,对于有参的使用要注意如果构造函数使用的是int那么在获取构造函数的时候就也要写int.class而非是Interger.class
6、反射使用的几个步骤
- 获取对象的Class
- 获取类中的各种元素——构造函数、属性、方法
- 对获取到的属性进行使用,如果我们使用的对象中的具体内容则应该指明那个对象
6、BeanUtils的使用
//将以及赋值过或是没有找到匹配值的Field对象移除减少下次比较的次数,在多Field的情况或可提高效率
public static void convert2(Object origObj,Object targetObj) throws IllegalAccessException {
//获取两个对象的属性列表
LinkedList<Field> origFields = new LinkedList<Field>(Arrays.asList(origObj.getClass().getDeclaredFields()));
LinkedList<Field> targFields = new LinkedList<Field>(Arrays.asList(targetObj.getClass().getDeclaredFields()));
Field targetTempField,origTempField = null;
Iterator<Field> iterator = null;
while (targFields.size()>0){
targetTempField = targFields.pop();
iterator = origFields.iterator();
while (iterator.hasNext()){
origTempField = iterator.next();
if (targetTempField.getName().equals(origTempField.getName())){
targetTempField.setAccessible(true);
origTempField.setAccessible(true);
targetTempField.set(targetObj,origTempField.get(origObj));
iterator.remove();
}
}
}
}