JAVA 使用反射进行动态编译

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liuajiehe1234567/article/details/78493657

在开始码博文之前,写一点题外话 博主现在大四在读,报了培训班学习java,目前上了两个月的课程,对培训班出身的程序员优势劣势略有体会。
反射呢,老师在讲之前,说理解这个东西有些难度,就只教了使用方法(即简单的获取类信息/对象),并没有结合JMM和JAVA语言的特性来细说反射
是什么 和 为什么需要反射,动态编译也是,培训的老师将项目框架搭好,让你熟悉分层和面向接口编程设计。
在这之前(哪怕之后)却并没有细说设计模式的概念和各模式设计的优劣,这样一来,四个半月速成一个会写业务逻辑的JAVA程序员是没有问题,但是不与硬件结合讲解内存分配机制和语法结构,甚至闭口不提这些上升空间,其实相比科班出身,善于自学的程序员们,是有很大劣势的

以下内容全部来自博主查找的资料,如有纰漏,欢迎指正
首先是动态编译,什么是叫做动态编译,这涉及到程序设计模式的问题,一般来说,我们设计一个JAVA程序/项目,会经过以下过程

  1. 需求分析
  2. 确定业务逻辑和算法
  3. 搭建框架(或者使用现成的)和业务接口
  4. 面向接口编程
    其中业务接口需要写它的实现类来实现业务吧,比如在业务层的UserService接口写了方法,那么我就需要一个UserServiceImpl的接口实现类来实现它,然后再在表现层调用这个接口实现类中的方法来实现业务,但是在当前类中调用一个另一个类中的方法时,要不然就创建一个此类对象进行方法调用,要不然就把这个类的方法写成静态方法。

为什么不写成静态的这里不再赘述,感兴趣的可以看我的下一篇博文。
在需要接口实现类时,应尽量避免去在需要一个类的时候直接去new它。
当new一个类的时候,需要一个它的类名来对其实例化,假设USerService是一个接口,UserServiceImpl是它的实现类,如果在需要调用它方法的时候直接new就是:

UserService us= new UserServiceImpl()

这段代码可以发生在很多地方,工厂类中、接口实现类中、调用时…在业务实现上没有区别
但在编码时,使用接口实现类的类名来直接实例化这个接口实现类对象。这样有三个坏处

  1. 不利于代码模块化(即高内聚,低耦合),类与类之间过分依赖。
  2. 不管这个接口实现类是由工厂类中制作由静态方法提供,还是直接在类下添加单例进行调用,都会需要将此接口实现类类名进行硬编码(即写死在代码里)
  3. 增加了代码量,因为这意味着每写一个接口实现类,就需要一段构造一个此类对象的代码和调用方法

反射能在运行时通过类的路径和类名来动态获取类的信息,获取类对象是它功能的一种
先看一段代码

UserService us = Class.forName("com.day01.UserServiceImpl");
//这里通过传入一个字符串获取了接口实现类对象

类路径名字符串肯定是没必要每次都写的
可以把它和类名对应的写到properties或者XML配置文件中,文件对象的创建就放到静态代码块里确保类加载时就将内容读入内存,另外很关键的一点是使用反射获取的对象依然是通过对象本身的构造方法构造的,它同样会占用内存。所以当有大量接口实现类需要获取时,推荐在工厂类中创建一个静态的map集合来存储接口名和唯一接口实现类

private static Map<String,Object> classmap = new HashMap<String,Object>();
    static{
        //通过工具类获取Properties键值对列表
        //通过列表,获取类名与类对应路径,通过类对应路径,将实现类放到map集合中
        Properties prop = new Properties();
        prop.load(new FileInputStream(new File("com.prop.classANDpath.properties")))
        Set<String> set = prop.stringPropertyNames();
        for(String str:set){
            try {
                classmap.put(str, Class.forName(prop.getProperty(str)).newInstance());
            } catch (Exception e) {
                //三个可能异常
                //1.类转换异常
                //2.类查找异常
                //3.非法权限异常IlligalAccessException,当实现类构造方法被私有化时会抛出这个异常
                e.printStackTrace();
            } 
        }
    }

    //传入一个需求类接口的字符串名,然后返回一个此字符串名对应的接口实现类
    public static Object getInstance(String ClassName){
        Object o = null;
        o = classmap.get(ClassName);
        return o;
    }

在业务上,如果有接口多实现,也不难通过此方法获取实现类,如果是多实现,传入的就应该是接口实现类的类名了

一个疑问:这里使用一个静态的map集合来实现单例到底对不对,在多线程时有影响吗?现在还没有写过多线程项目,所以…..
未完待续

猜你喜欢

转载自blog.csdn.net/liuajiehe1234567/article/details/78493657