Reflection反射机制原理使用场景 及 缺陷

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Reflection反射机制原理使用场景 及 缺陷相关的知识,希望对你有一定的参考价值。

(目录)


反射

一个需求 引出反射

需求如下:

根据配置文件re.properties中的指定信息,创建Cat对象并调用方法hi


代码如下:

public class Cat 
    private String name;
    public int age;
    public String sex;
 
    //无参构造器
    public Cat() 
    private Cat(String name)
        this.name = name;
    
    
    public Cat(String name, int age, String sex) 
        this.name = name;
        this.age = age;
        this.sex = sex;
    
 
    public void hi() 
        System.out.println("hi:" + name);
    
    
    public void eat(String food) 
        System.out.println(name+": 吃"+food);
    
    public int sum(int x, int y) 
        return x+y;
    
    public void dosome(int x,float y, char z, boolean b, String... strs)
        System.out.println(name+": "+x+" "+y+" "+z+" "+b);
        System.out.println(name+": "+strs);
    
    private void WC() 
        System.out.println(name + ": 上厕所..");
    
 
    @Override
    public String toString() 
        return "Cat" +
                "name=" + name + \\ +
                ", age=" + age +
                ", sex=" + sex + \\ +
                ;
    


// 反射问题的引入
//根据 re.properties 配置文件中的信息,创建Cat对象并调用hi方法
public class ReflectionQuestion 

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException 
        //传统方式:new 对象 --》 调用方法 Cat().hi();

        // 1. 传统方法: 使用Properties类读写配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src/main/resources/re.properties"));
        String classfullpath = properties.get("classfullpath").toString(); //com.panyujie.reflection.Cat
        String methodName = properties.get("method").toString(); //hi
        System.out.println("classfullpath=" + classfullpath);
        System.out.println("methodName=" + methodName);

        // 2. 创建对象
        // 怎么创建对象???? 你拿到了类的全路径 你怎么 new?
        // 只能使用 反射机制
        // 2.1 加载类,返回Class类型的对象
        Class<?> cls = Class.forName(classfullpath);
        // 2.2 通过 cls对象 得到加载的类 com.panyujie.reflection.Cat 的对象
        Object o = cls.newInstance();
        // 2.3 通过 cls对象 得到加载的类 com.panyujie.reflection.Cat 的 methodName 方法对象 hi
        // 即:在反射机制中,可以把方法视为对象(万物皆对象)
        Method method1 = cls.getMethod(methodName);
        // 2.4通过 method1 调用方法:即-》通过方法对象实现调用方法
        // 反射机制:方法.invoke(对象)
        method1.invoke(o);
    


效果: 调用成功,为null是因为我没赋值

此时我们发现,我们只需要将re.properties中的 method=hi 改成 method=eat,就会调用eat(),不需要修改源码,反射机制非常强大!


反射机制

Java Reflection


反射机制 原理图


反射机制可以完成的功能


反射相关的主要类


  1. 测试Field和Constructor:
        //java.lang.reflect.Field: 代表类的成员变量, Field对象表示某个类的成员变量
        //得到name字段
        //getField不能得到私有的属性
        Field nameField = cls.getField("age"); //
        System.out.println(nameField.get(o)); // 传统写法 对象.成员变量 , 反射 :  成员变量对象.get(对象)

        //java.lang.reflect.Constructor: 代表类的构造方法, Constructor对象表示构造器
        Constructor constructor = cls.getConstructor(); //()中可以指定构造器参数类型, 返回无参构造器
        System.out.println(constructor);//Cat()
public class Cat 

    private String name = "招财猫";
    public int age = 10; //public的

    public Cat()  //无参构造器

    public Cat(String name) 
        this.name = name;
    

    public void hi()  //常用方法
        //System.out.println("hi " + name);
    
    public void cry()  //常用方法
        System.out.println(name + " 喵喵叫..");
    


测试Field和Constructor得到的结果:


  1. 获得有参数的构造器
//传入 String.class 就是String类的Class对象
Constructor constructor2 = cls.getConstructor(String.class); 
System.out.println(constructor2);//Cat(String name)


反射优点 和 缺点


反射调用 性能测试 及 关闭访问检测

测试代码:


/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Submerge
 * Date: 2022-10-23
 * Time: 18:10
 * 测试反射调用的性能
 */
public class Reflection2 

    public static void main(String[] args) throws Exception 
        m1();
        m2();
    

    // 普通调用方法
    public static void m1()
        Cat cat = new Cat();
        long l = System.currentTimeMillis();
        for(int i=0;i<50000000;i++)
            cat.hi();
        
        long r = System.currentTimeMillis();
        System.out.println("普通调用耗时: " + (r-l));
    

    // 反射调用方法
    public static void m2() throws Exception 

        Class<?> cls = Class.forName("com.panyujie.reflection.Cat");
        Object o = cls.newInstance();
        Method hi = cls.getMethod("hi");
        long l = System.currentTimeMillis();
        for(int i=0;i<50000000;i++)
            hi.invoke(o);
        
        long r = System.currentTimeMillis();
        System.out.println("反射调用耗时: " + (r-l));
    



测试结果:反射对速度影响还是挺到的


    //反射调用优化:关闭访问检测
    public static void m3() throws Exception 
        Class<?> cls = Class.forName("com.panyujie.reflection.Cat");
        Object o = cls.newInstance();
        Method hi = cls.getMethod("hi");
        //在反射调用方法时,取消访问检查
        hi.setAccessible(true);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 50000000; i++) 
            hi.invoke(o);
        
        long end = System.currentTimeMillis();
        System.out.println("关闭访问检测反射耗时:" + (end - start));
    



@

以上是关于Reflection反射机制原理使用场景 及 缺陷的主要内容,如果未能解决你的问题,请参考以下文章

Java Reflection (JAVA反射)机制详解

Java--反射机制原理几种Class获取方式及应用场景

反射机制(Reflection)

深入理解java的反射机制

反射Reflection

Go - reflection