JDK源码/*分析 :反射包 java.lang.reflect 之 Class 探秘

时间:2021-03-07 15:24:03
其实 Class 并不在 java.lang.reflect 中,它的全限定名为: java.lang.Class 。

Class 是什么?
它和我们平时写的代码中的类一样,对它么的它就是一个类。它有属性有方法,别想得它有什么特别的地方,我就告诉你它不特别,它就是一个类。

这个类是干什么用的呢?它是用来表示其他类的信息的类。是不是有点绕,我来说慢点:Class 这个类的实例,就是表示其他类(包括它自己)信息的。类信息的意思就是,这个类有什么属性,属性的权限是什么,属性的类型是什么,有什么方法,方法的权限是什么,入参是什么,返回值是什么。烦是你在*.java这个文件中看得到的信息就叫类的信息。反向来讲就是,从Class 的实例中可以知道*.java长什么样子。

如何得到类的Class 对象实例?
首先,它的构造方法只有一个,而且还是私有的。
  private Class(ClassLoader paramClassLoader )
  {
    this . classLoader = paramClassLoader ;
  }
所以它是没法new 出来的。据我所有,它可以有两种方式得到。
1. Class<?> clzz = Class. forName ( "java.lang.Class" );
这是在知道类的全限定名(包.名)的情况获得的。
2. TestClass tt = new TestClass();
  Class<?> ttclzz = tt .getClass();
这是在得到类的实例的情况,也可以获得。其实得到Class 对象后也可以得到该对象代表的类的实例。
TestClass instance = (TestClass) clzz .newInstance();

Class --> 实例;实例-->Class 。

所谓的反射,就像是: Class --> 实例,这种情况,但这不是反射的定义 。
3.Class<?> clzz = TestClass.class;
这种是最容易但也是最容易被人忘却的方式。

上面这三种方式得到Class 实例都要做同一件事,也是想要获取其他所有实例都要做的一件事。它是什么呢?

得到Class 实例所要做的事
其实这件事在说JVM 的时候已经有说过了,那就是从 类的 二进制字节码中 将 类信息 加载、验证等一系列操作放到JVM内存中来。

得到Class 实例后我们可以做什么?
前面说过了, Class 实例 就是某类 代号A 的信息。这些信息 我们当然可以一个个列出来啊,所以Class类中有相应的方法帮我们做这些事。

ClassLoader cd = clzz .getClassLoader();
得到加载这个类 A 的 类加载器
Field[] fd = clzz .getFields();
得到这个 类 A的所有公共的属性
Field [] fd  = clzz .getDeclaredFields();
得到这个类 A的所有属性
Method[] fm = clzz .getMethods();
得到这个类 A的所有公共的方法

等等。烦是你能从 *.java 中得到的信息这个 Class 对象都能得到。

Class 这个类什么用?
我们学Java 之初就有人告诉我们 Java 类 就是对某种事物的抽象,万物皆对象。这句话是非常正解的,只是大家可能都是知道这句话的意思,但并不知道如何运用这个道理(知道的道理很多,却依然看不清事情的本质)。这个 Class 类抽象的 就是这世界所有的 Java 类(包括它自己)。

它有什么秒用呢,我还是习惯形象地举个例子。

一般我们获取对象的方式:
    ClassA a = new ClassA();
    ClassB b = new ClassB();
    ClassC c = new ClassC();
    ClassD d = new ClassD();
    ...(后续还有几百行)
    依次类推,发挥你的想象这里new 了几百个对象。

有了Class 之后  :

    for (String classFullName : classFullNameList)  {
        Class<?> clzz = Class.forName( classFullName );
    }

    后续再无代码。

这就是反射机制。它可以动态地生成实例对象,还不需要使用它的构造函数来生成 。仔细分析的话,道理是非常简单的。区别就是前一种方式它把 类 的名写死在代码了;而后一种则是通过传参的方式,从其他地方得到 类 的名字。其实这是所谓的解耦思想,增加更多的灵活性。这种获取实例的方式是很多框架用到的,因为框架并不知道你会写什么类。