Java 反射

对于Class类的理解

注意,这里的Class和关键词class是两码事。这里的Class是一个类,它的实例就是我们平常使用的类如Person,Dog。如果说运行时类是对日常事物的一个抽象,Class可以理解为对运行时类类的进一步抽象。

创建Class的实例

调用运行时类的属性 .class

1
Class<Person> clazz = Person.class;

调用运行时类对象的getClass()

1
2
3
Person person = new Person("Ando", 19);
Class<? extends Person> clazz2 = person.getClass();
System.out.println(clazz2);

调用Class的静态方法:forName(String classPath)

1
2
Class<?> clazz3 = Class.forName("Person");
System.out.println(clazz3);

这三种方法获取到的运行时类均为同一个

类加载过程

当程序使用到某个类,且该类还未被加载进内存中,则系统通过下列步骤对类进行初始化:

  • 类的加载:将类的class文件转化为某种静态数据结构,存储在方法区,并为之在中创造一个java.lang.Class对象

  • 类的链接:分为验证,准备,解析三个阶段。验证:元数据和字节码的验证(语法和语义的分析,确保该class对虚拟机安全)等验证机制。准备:为该类中定义的静态变量附0值。解析:将符号引用变为直接引用

  • 类的初始化:为静态变量进行赋值

ClassLoader

类加载器作用是用来将类加载进内存的。JVM规范定义了如下类型的加载器:

引导类加载器:负责java核心平台库(如String等关键类),无法直接获取

拓展类加载器:负责jre/lib/ext目录下等jar包里的类

系统类加载器:负责自己定义的类

自下向上检查是类已经加载,自上向下尝试进行类加载

1
2
3
4
5
ClassLoader classLoader = Person.class.getClassLoader();
System.out.println(classLoader);

ClassLoader classLoader2 = String.class.getClassLoader();
System.out.println(classLoader2);

创建运行时类对象

1
2
Class<Person> personClass = Person.class;
Person person = personClass.getDeclaredConstructor().newInstance();

personClass.newInstance在jdk1.9之后被弃用,使用person.getDeclaredConstructor().newInstance()

使用该方法的要求:

  • 运行时类必须提供空参的构造器
  • 具有空参的构造器的访问权限

反射的动态性

利用反射我们可以在运行时根据不同的情况,为变量classPath赋不同的值,再用Class.forName(classPath)进行创建。这体现了反射的动态性。