01-Java反射的原理与使用

本文详细介绍了Java反射机制,包括为何需要反射、类的加载过程、反射的结构图和Class文件组成。通过三种方式获取Class对象,并展示了Field和Constructor的获取技巧,如设置访问权限。此外,讨论了访问修饰符的权限范围,并通过实例演示了反射在创建对象、访问成员变量和构造函数中的应用。最后,提到了BeanUtils在反射操作中的使用。

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();
                }
            }
        }
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值