zoukankan      html  css  js  c++  java
  • Java知识系列 -- 反射

    原理

    要想理解 Java 反射,首先要弄清类的加载过程。
    比如这行代码 Person p = new Person();
    我们想要创建一个 Person 对象,并用 p 作为对象的引用。
    在 Java 虚拟机会先执行类的加载,然后才生成对象(分配内存空间)。在类的加载过程中,类加载器负责把类编译好的 class (字节码)文件加入到内存中,并创建一个 Class 对象,这个对象是类 Class 的实例
    也就是说,上面的一行的代码看似只是创建了一个 Person 对象,但是如果是第一次使用该类,也即类加载器还未把该类的 class 文件加载到内存中时,还会创建一个Class 对象
    在 Java 中,一切都是对象。类是对一类对象的抽象,类是一个概念,而类本身也是一种对象,在 Java 中,它们是 Class 类的对象,当然方法、属性、注解也分别是 Method、Field、Annotation 的对象。
    所以,反射干的就是干预程序运行期做的事情。比如创建一个在编译期不能确定的类(子类)。

    在编码阶段不知道那个类名,这时候就没有办法硬编码new ClassName(),而必须用到反射才能创建这个对象。
    在xml文件或者properties里面写好配置,然后在Java类里面解析xml或properties里面的内容,得到一个字符串。
    然后用反射机制,根据这个字符串获得某个类的Class实例,这样就可以动态配置一些东西,不用每一次都要在代码里面去new或者做其他的事情。反射的目的就是为了扩展未知的应用。

    使用

    获取 Class 对象的三种方法

    Class 对象是我们使用反射的关键,而得到这个对象有下面三种方式。

    • 调用 Class 类的 forName() 静态方法
    • 调用类的隐藏类属性 class。
    • 使用对象来获取,调用祖先类 Object 中的方法:public final native Class<?> getClass()

    推荐使用第二种方式来获取 Class 对象,因为在编译期就会检查该类是否存在,更加安全,并且因为没有方法调用,使用的是属性,所以性能也更高。

    Class 对象中的方法

    可以说我们得到了 Class 对象,就得到了这个类的所有信息了。包括各种获取 构造方法、属性、方法、注解 的方法。

    其他常用方法

    public String getName() // 返回 Class 对象表示的类型(类、接口、数组或基本类型)的完整路径名字符串
    public T newInstance() // 此方法是 Java 语言 instanceof 操作的动态等价方法
    public ClassLoader getClassLoader() // 获取该类的类加载器
    public Class getSuperclass() // 返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class
    public boolean isArray() // 如果 Class 对象表示一个数组则返回 true, 否则返回 false
    public boolean isInterface() // 判定指定的 Class 对象是否表示一个接口类型
    public boolean isPrimitive() // 判定指定的 Class 对象是否表示一个 Java 的基本类型
    

    例子

    1. 在我们写代码时,在对象后面敲一个 . ,IDE 就会自动帮我们列出该对象有的方法,这里其实就是IDE使用了反射,通过对象找到该类对应的 Class 对象,从而就可以找到类中的属性和方法。

    2. JDBC操作数据库第一步加载数据库驱动, Class.forName("com.mysql.jdbc.Driver"),这里是 MySQL 数据库,假如某一天我们想换成 Oracle 数据库,你可能会修改 forName() 方法中的参数为 Oracle 数据库驱动名。

    3. 做一个软件可以安装插件的功能,不知道插件的类型名称,你怎么实例化这个对象呢?所以无法在代码中 New出来 ,但反射可以,通过反射,动态加载程序集,然后读出类,检查标记之后再实例化对象,就可以获得正确的类实例。(写了一个程序,这个程序定义了一些接口,只要实现了这些接口的dll都可以作为插件来插入到这个程序中。就可以通过反射来实现。就是把dll加载进内存,然后通过反射的方式来调用dll中的方法。很多工厂模式就是使用的反射。)

    项目应用

    配置文件存放需要反射的类信息:

    1. 使用xml或者prop存keyvalue形式
    2. 添加一个这样的类,来专门存放需要反射的映射关系
    public class Tables {
        public static final Map<String, String> tables = new HashMap<>();
        static {
            tables.put("PICRECORD", "com.stillcoolme.entity.PICRECORD");
        }
    }
    

    总结

    反射可以使我们的代码更具灵活性(运行期类型的判断,动态类加载,动态代理(以后再聊这个)),但是反射也会消耗更多的系统资源,所以如果不需要动态创建一个对象,那么就不需要用到反射。

  • 相关阅读:
    线程池原理和实现
    线程
    ajax、xstream、json
    上传、下载、javamail
    过滤器
    监听器、国际化
    jsp、javabean、el
    jstl、标签
    jsp、cookie、httpsession
    个人觉得比较好用的chrome插件
  • 原文地址:https://www.cnblogs.com/stillcoolme/p/9818573.html
Copyright © 2011-2022 走看看