反射

2019-12-11  本文已影响0人  couriravant

一、什么是反射

反射使程序代码能够接入装载到JVM中的类的内部信息,允许在编写与执行时,而不是源代码中选定的类协作的代码,是以开发效率换运行效率的一种手段。这使反射成为构建灵活应用的主要工具。

二、作用

  1. 调用一些私有方法,实现黑科技。比如双卡短信发送、设置状态栏颜色、自动挂电话等。

  2. 实现序列化与反序列化,比如PO的ORM,Json解析等。

  3. 实现跨平台兼容,比如JDK中的SocketImpl的实现

  4. 通过xml或注解,实现依赖注入(DI),注解处理,动态代理,单元测试等功能。比如Retrofit、Spring或者Dagger

三、基本使用

代码块

package com.example.myapplication.reflect;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Apple {

    private String appleName;
    private int price;
    private static final String name = new String("巫婆的苹果");

    private Apple() {}

    private Apple (String appleName, int price) {
        this.appleName = appleName;
        this.price = price;
    }

    private void setPrice(int price) {
        this.price = price;
    }

    private int getPrice () {
        return price;
    }

    private String getName() {
        return name;
    }

    public static void main(String[] args) {
        Apple apple = new Apple();

        try {
            //三种获取Class的方法,反射主要用第一种
            Class clz = Class.forName("com.example.myapplication.reflect.Apple");
            Class clz1 = apple.getClass();
            Class clz2 = Apple.class;

            //获取类实例的两种方法
            Apple apple1 = (Apple) clz.newInstance();
            Apple apple2 = (Apple)clz1.getDeclaredConstructor(String.class, int.class).newInstance("白雪公主", 1000);
            System.out.println("apple name:"+apple2.appleName);

            //获取方法对象
            Method method = clz.getDeclaredMethod("setPrice", int.class);
            method.setAccessible(true);
            method.invoke(apple1, 5);

            Method getMethod = clz.getDeclaredMethod("getPrice");
            getMethod.setAccessible(true);
            System.out.println("反射方法对象获取price"+getMethod.invoke(apple1));

            //遍历方法
            Method[] methods = clz.getDeclaredMethods();
            AccessibleObject.setAccessible(methods,true);

            for(Method method1 :methods) {
//                method1.setAccessible(true);
                System.out.println("类中的方法有:"+method1.getName());
            }

            //获取变量
            Field field = clz.getDeclaredField("price");
            field.setAccessible(true);
            int newPrice = field.getInt(apple1);
            System.out.println("直接反射变量获取到的price"+newPrice);

            //遍历变量
            for(Field field1 : clz.getDeclaredFields()) {
                field1.setAccessible(true);
                System.out.println("获取到的变量名:"+field1.getName());
            }

            //获取final变量 ,被内联的没用,这样似乎也没什么用,上面的new String("巫婆的苹果") 是为了防止内联
            Field nameField = apple1.getClass().getDeclaredField("name");
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(nameField, nameField.getModifiers() & ~Modifier.FINAL);
            nameField.setAccessible(true); //这个同样不能少,除非上面把 private 也拿掉了,可能还得 public
            nameField.set(null, "巫婆的第二个苹果");
            System.out.println("修改final变量后 "+apple1.getName());

        } catch (Exception e) {
            System.out.println("exception:"+e.getMessage());
        }
    }
}

输出:

apple name:白雪公主
反射方法对象获取price5
类中的方法有:main
类中的方法有:getName
类中的方法有:getPrice
类中的方法有:setPrice
直接反射变量获取到的price5
获取到的变量名:appleName
获取到的变量名:price
获取到的变量名:name
修改final变量后 巫婆的第二个苹果

四、怎么理解反射慢

在Stackoverflow上认为反射比较慢的程序员主要有如下看法

  1. 验证等防御代码过于繁琐,这一步本来在link阶段,现在却在计算时进行验证

  2. 产生很多临时对象,造成GC与计算时间消耗

  3. 由于缺少上下文,丢失了很多运行时的优化,比如JIT(它可以看作JVM的重要评测标准之一)

当然,现代JVM也不是非常慢了,它能够对反射代码进行缓存以及通过方法计数器同样实现JIT优化,所以反射不一定慢。

优化反射:

为什么反射慢:
1)getMethod和getDeclaredField方法会比invoke和set方法耗时;

2)随着测试数量级越大,性能差异的比例越趋于稳定;

如何优化:

1)善用API
比如,尽量不要getMethods()后再遍历筛选,而直接用getMethod(methodName)来根据方法名获取方法。
2)缓存大法好
比如,需要多次动态创建一个类的实例的时候,有缓存的写法会比没有缓存要快很多。还有将反射得到的method/field/constructor对象做缓存。
3) 尽量使用高版本jdk
4)ReflectASM通过字节码生成的方式加快反射速度

refer:
http://www.throwable.club/2018/12/16/java-reflection-optimal-performance/#%E6%96%B9%E6%B3%95%E4%B8%89%EF%BC%9A%E5%8F%8D%E5%B0%84%E6%93%8D%E4%BD%9C%E8%BD%AC%E5%8F%98%E4%B8%BA%E7%9B%B4%E6%8E%A5%E8%B0%83%E7%94%A8

http://www.importnew.com/21211.html
https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html

上一篇下一篇

猜你喜欢

热点阅读