Java反射技术

写在前面

忙碌的一学期又结束了,最近也是重新拾起了好久不用的Java为秋招做些准备。
首先谈谈反射,在大学学设计模式时听得一知半解,最近重新温习一下。
本文参考自:

https://blog.youkuaiyun.com/qq_44614710/article/details/86741226
https://blog.youkuaiyun.com/grandgrandpa/article/details/84832343

什么是反射

Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

Java中有两种编译类型:

  • 静态编译:在编译时确定类型,绑定对象即通过。
  • 动态编译:运行时确定类型,绑定对象。动态编译最大限度地发挥了Java的灵活性,体现了多态的应用,可以减低类之间的耦合性。

也就是说,通过new关键字创建对象,则属于静态编译,因为在编译时就已经确定。
通过反射可以在程序运行过程中动态地操作对象,可以获得编译期无法获得的信息。
反射是Java被视为动态(或准动态)语言的一个关键性质,可以有效地降低类之间的耦合。

如何实现

在这里插入图片描述
上图是在静态编译的情况下计算机实际要做的事情。
想要实现反射,就必须先拿到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息,每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。

1. 获取字节码文件对象(Class)的三种方式

/**
     * 方式一:
     * Object中的getClass方法来获取Class对象
     * 使用这种方式必须有具体的类,并创建对象。
     * 这种方式使用的少,一般是传的是Object,不知道类型的时候才使用。
     */
            Object obj = new Person();
	        Class clazz1 = obj.getClass();

   /**
     * 方式二:
     * 直接通过 类名.class 来获取Class对象。
     * 任何类型中都具有隐含的静态成员变量class,使用简单,但是扩展性还是不足。
     */
            Class clazz2 = Person.class;

  /**
     * 方式三:
     * 通过Class 对象的forName()静态方法来获取Class对象。
     * 使用最多,通过类的全限定名,但可能抛出ClassNotFoundException异常
     */
            Class clazz3 = Class.forName("包名.类名");
 

由于一个类在JVM中只有一个Class实例,所以创建的三个对象均相同。

2. 创建对象的方式

实例化对象的方式

         // 不用反射: 需要手动new对象不能动态创建。
	     // 根据new的类名寻找字节码文件,加载进入内存,创建Class对象,并接着创建对应的Person对象。 
         Person p = new Person();

        // 通过反射:只需要一个名字,就可以创建对象。
        String className = "类名.包名";
        // 寻找该名称的类文件,加载进内存,并创建Class对象。
        Class clazz = Class.forName(className);
        // 通过Class对象的newInstance()创建类对象。
        Object o = clazz.newInstance();

初始化变量的方式

        // 不用反射:通过构造方法实例化并初始化变量
        Object obj1 = new Person("name", 18);
        
        // 通过反射:Class对象的getConstructor方法拿到构造器。
        Constructor constructor = clazz.getConstructor(String.class, Integer.class);
        // 通过构造器的newInstance方法实例化并初始化变量
        Object obj2 = constructor.newInstance("name2", 22);

Class类中常用方法

获取公共构造器 getConstructors()
获取所有构造器 getDeclaredConstructors()
获取该类对象 newInstance()
获取类名包含包路径 getName()
获取类名不包含包路径 getSimpleName()
获取类公共类型的所有属性 getFields()
获取类的所有属性 getDeclaredFields()
获取类公共类型的指定属性 getField(String name)
获取类全部类型的指定属性 getDeclaredField(String name)
获取类公共类型的方法 getMethods()
获取类的所有方法 getDeclaredMethods()
获得类的特定公共类型方法: getMethod(String name, Class[] parameterTypes)
获取内部类 getDeclaredClasses()
获取外部类 getDeclaringClass()
获取修饰符 getModifiers()
获取所在包 getPackage()
获取所实现的接口 getInterfaces()

        // 获得类完整的名字
        String className1 = clazz2.getName();
        System.err.println("类完整的名字: " + className1);

        // 获得类名不包含包路径
        String className2 = clazz2.getSimpleName();
        System.err.println("类名不含路径: " + className2);

        // 获得类中公共类型(public)属性
        Field[] fields = clazz2.getFields();
        String fieldName = "";
        for(Field field : fields) {
            fieldName += field.getName() + "  ";
        }
        System.err.println("类中公共属性: " + fieldName);

        // 获得类中全部类型(包括私有)属性
        Field[] fieldsAll = clazz2.getDeclaredFields();
        fieldName = "";
        for(Field field : fieldsAll){
            fieldName += field.getName() + "  ";
        }
        System.err.println("类中全部属性: " + fieldName);

        // 获得公共指定属性值
        Field age = clazz2.getField("age");
        Object o = age.get(obj);
        System.err.println("公共指定属性: " + o);

        // 获得私有指定属性值
        Field name = clazz2.getDeclaredField("name");       
        name.setAccessible(true); //设置为true才能获取私有属性
        Object o2 = name.get(obj);
        System.err.println("类中私有指定属性值: " + o2);

        // 获取类所有公共类型方法,这里包括 Object 类的一些方法
        Method[] methods = clazz2.getMethods();
        String methodsName = "";
        for(Method method : methods){
            methodsName += method.getName() + "  ";
        }
        System.err.println("类公共类型方法: " + methodsName);

        // 获取该类中的所有方法(包括私有)
        Method[] methodsAll = clazz2.getDeclaredMethods();
        methodsName = "";
        for(Method method : methodsAll){
            methodsName += method.getName() + "  ";
        }
        System.err.println("类中的所有方法: " + methodsName);

        // 获取并使用指定方法
        Method method1 = clazz2.getDeclaredMethod("method1"); //获取无参私有方法
        method1.setAccessible(true); //设置为true才能获取私有方法
        method1.invoke(obj); //调用无参方法

        Method method2 = clazz2.getMethod("method2", String.class); //获取有参数方法
        method2.invoke(obj, "666"); //调用有参方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值