文章目录
1 类是如何从.class文件到JVM可以使用
1.1 JVM
当我们启动某个Java程序时,将会在系统中启动一条Java虚拟机进程,不管该Java程序有多复杂,它们都处于这个Java虚拟机中。
JVM进程终止的情况:
- 程序正常结束。
- 程序运行到
System.exit()
或者Runtime.getRuntime().exit()
代码结束。 - 程序运行过程中遇到未被捕获的异常或者错误,程序结束。
- JVM运行的平台强制结束了JVM进程。比如linux下用kill命令强制结束某个进程。
1.2 JVM加载类
当JVM主动使用某个类,且该类还未被加载到内存中,系统就会通过加载、连接、初始化三步来把该类加载到内存。
- 加载:将类的
.class
文件读入到内存,并为其创建一个java.lang.Class
对象。 - 连接:把类的二进制数据合并到JRE中。该阶段又分为验证、准备、解析。
- 初始化:对类的静态属性进行初始化。
1.2.1 JVM什么时候加载某个类
当程序通过以下六种方式来使用某个类或者接口时,JVM主动加载该类或者接口:
- 创建类的对象。有通过new操作符来创建对象,通过反射创建对象,通过反序列化创建对象。
- 调用某个类的静态方法
- 调用某个类的静态属性,或者为该属性赋值。
- 通过反射方式强制创建某个类或者接口对应的
java.lang.Class
对象。比如前面的Class.forName("com.mysql.jdbc.Driver")
,如果JVM还未加载Driver
类,这段代码就会将该类初始化,并返回Driver类对应的java.lang.Class对象。 - 初始化某个类的子类。当JVM需要初始化某个类的,其所有的父类都会被初始化。
- 直接使用java.exe来运行某个主类,JVM会初始化该主类。
1.2.2 类加载器加载类
类的加载由类加载器完成。
类加载器加载二进制数据来源:
- 本地文件系统来加载class文件
- 从jar包中加载class文件。通常是我们使用非jdk提供的类,比如使用JDBC要用到的mysql驱动。
- 通过网络加载(我用的比较少)
- 把一个Java源文件动态编译、并加载
类加载器加载类的时机:看JVM的设置
1.2.3 连接
连接负责将类的二进制数据合并到jre中。整个过程分为三步:
- 验证:检测被加载的类是否有正确的内部结构,并且和其他类协调一致。
- 准备:负责为类的静态属性分配内存,并且设置默认初始值。
- 解析:将类的二进制数据中的符号引用替换为直接引用。(这里不太懂)
1.2.4 类的初始化
2. 反射
2.1 获得类的Class对象
每个类被加载后,系统会为该类生成一个对应的Class对象。获取Class对象的方式有:
- 使用Class的
forName()
静态方法。参数为类的全限定类名的字符串。 - 调用某个类的class属性。如
Person.class
的值就是Person对应的Class对象。 - 调用对象的
getClass()
方法。
2.2 从Class对象中获取信息
获取构造器:
Connstructor<T> getConstructor(Class<?>... parameterTypes)
: