• 反射


    java中java语言的反射机制:

    java反射机制在运行状态中,对于任意一个类(class文件),都能知道这个类的所有属性和方法;

    对于任意一个对象,能够调用它的任意一个方法和属性:

    这种动态获取的信息以及动态调用对象的方法的动能称为java语言的反射机制。

     

    动态获取类中信息,就是java反射,可以理解对类的解剖。有些应用程序是不能new对象的,但是可以动态加载类获取类信息。

     如图所示,就像类是对象的描述一样,Class类可以对字节码文件(.class文件)对象进行描述。

    //早期:new时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存,
    //并创建该字节码文件对象,并接着创建该字节码文件的对应的Person对象。
    com.xidian.Person p=new com.xidian.Person();

    //现在
    String name="com.xidian.Person";
    //找寻该文件类文件,并加载进内存,并产生Class对象。
    Class clazz=Class.forName(name);
    //如何产生该类的对象呢?
    Object obj=clazz.newInstance();

    用反射类加载的方式,从表面上看形式较为复杂但是可扩展性却更强。原来需要自己在程序文件手动中创建一个对象,

    现在只用在配置文件中写入字符串,就可以创建对应的对象。

     

    问题:使用clazz.newInstance()只能使用空参构造函数,要使用参数列表的构造函数怎么办?

    /*
    * 获取指定名称对应类中的所体现的对象时,
    * 而该对象初始化不使用空参构造函数该怎么办?
    *
    * 既然是通过指定的构造函数进行对象的初始化,
    * 所以应该先获得到该构造函数。通过字节码文件即可完成。
    * 该方法是:getConstructor(parameterTypes)
    *
    * 在反射中构造器、字段、方法都是对象。
    */

    String name="com.xidian.Person";
    Class clazz=Class.forName(name);
    //获取到指定的构造函数对象
    Constructor constructor=clazz.getConstructor(String.class,int.class); //所有数据类型都可以用字节码文件.class来描述
    //通过该构造器对象的newInstance方法进行对象的初始化。
    Object obj=constructor.newInstance("xiaoming",12);

     

     获取指定字段的值:

    //对私有字段的访问全校权限检查。暴力访问。
    field_1.setAccessible(true);

    Object obj=clazz.newInstance();
    field_1.set(obj,88);

    Object o=field_1.get(obj);

    System.out.println(o);

     

    获取函数:

    Method method=clazz.getMethod("show",null); //获取无参的方法
    Object obj=clazz.newInstance();
    method.invoke(obj, null);

    Method method2=clazz.getMethod("paramMethod",String.class,int.class); //获取有参的方法,方法名、参数列表
    Object obj2=clazz.newInstance();
    method2.invoke(obj2, "小强",89); //invoke:对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

    反射的应用:

    定义一个接口:

    package com.xidian;
    public interface PCI {
        public void open();
        public void close();
    }

    定义一个接口实现类:

    package com.xidian;
    public class SoundCard implements PCI{
        
        public void open(){
            System.out.println("sound open");
        }
        
        public void close(){
            System.out.println("sound close");
        }
    
    }

    定义一个主板:

    package com.xidian;
    public class Mainboard {
        
        public void run(){
            System.out.println("main run...");
        }    
        public void usePCI(PCI p){
        if(p!=null){
            p.open();
            p.close();
        }
        }
    }

    测试:

    package com.xidian;
    
    public class Test {
        
        public static void main(String[] args){
            Mainboard mb=new Mainboard();
            mb.run();
            mb.usePCI(new SoundCard());      //如果主板需要使用其他设备,必须重新修改代码,传递一个新创建的对象,可扩展性不好。
            
        }
    }

    虽然使用接口的方式已经降低了程序的耦合度,但是代码的可扩展性不好。

    如果想增加主板的设备但是不想修改代码,改用反射的方式:

    不用new来完成,而是只获取其class文件,在其内部是实现创建对象的动作。

     用反射做配置是应该使用.xml,更加准确。而在此我们使用properties对象实现。

     修改主函数代码:

    public class Test {
        
        public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException{
            Mainboard mb=new Mainboard();
            mb.run();
            //mb.usePCI(new SoundCard());      //如果主板需要使用其他设备,必须重新修改代码,可扩展性不好。
                                                   
            File configFile=new File("pci.properties");
            
            Properties prop=new Properties();             //注意是将配置文件放在项目的一级目录下。
            FileInputStream fis=new FileInputStream(configFile);
            
            prop.load(fis);
            
            for(int x=0;x<prop.size();x++){
                String pciName=prop.getProperty("pci"+(x+1));
                Class clazz=Class.forName(pciName);
                PCI p=(PCI)clazz.newInstance();
                mb.usePCI(p);
            }
            
            fis.close();
        }
    }

    配置文件pci.properties:pci1=com.xidian.SoundCard

    当扩展设备的时候,只需要将设备程序写好,写好配置文件,而不需要改动主程序代码就可使用。

    这有一篇讲解反射写得非常好的一篇文章,尤其是用反射机制大致构建类似Mybatis框架的例子,非常受益。

    Java反射机制

  • 相关阅读:
    Spring Data Rest如何暴露ID字段
    Windows空间清理2
    把爱好变成职业
    面对面的口头信息传递对人决策的影响力最大
    最好是更好的敌人
    文明主线
    钱的本质
    2019第42周日
    开源与商业化
    生涯四度
  • 原文地址:https://www.cnblogs.com/xiangkejin/p/5966116.html
Copyright © 2020-2023  润新知