一.类的加载 连接和初始化
1.JVM和类
当我们调用Java命令运行某个Java程序时, 该命令会启动一条Java虚拟机进程, 不管该Java程序有多复杂, 改程序启动了多少个线程, 它们都处于Java虚拟机进程里, 同一个JVM的所有线程, 所有变量都处于同一个进程里, 它们都使用该JVM进程的内存区. 当系统出现以下几种情况时, JVM进程将被终止:
(1)程序运行到最后正常结束.
(2)程序运行到使用System.exit()或Runtime.getRuntime().exit()代码结束程序.
(3)程序执行过程中遇到未捕获的异常或者错误结束.
(4)程序所在平台强制结束了JVM进程.
当第二个程序再次输出A类的静态属性时, 值为6, 因为运行TestA1和TEstA2是两次JVM进程, 第一个JVM进程运行结束之后, 它对A类所做的修改将全部丢失, 第二次运行JVM时将再次初始化A类. 两次运行Java程序处于两个不同的JVM进程里面, 两个JVM不会共享数据.
2.类的加载
当程序主动使用某个类时, 如果该类还未被加载到内存中去, 系统会通过加载, 连接, 初始化三个步骤来对该类进行初始化, JVM会连续完成这三个步骤, 所以有时将这三步骤称为类加载或类初始化.
类加载指的是将类的class文件读入内存中, 并为之创建一个java.lang.Class对象, 程序在使用任何类时, 系统都会为之建立一个java.lang.Class对象. 每个类是一批具有相同特征的对象的抽象. 而系统中所有的类,它们实际上也是对象, 它们都是java.lang.Class的实例.
类的加载由类加载器完成, 类加载器通常由JVM提供, 这些类的加载器也是所有程序运行的基础, JVM提供的这些类加载器通常被称为系统类加载器, 开发者还可以通过继承ClassLoader基类来创建自己的类加载器.
3.类的连接
当类被加载之后, 系统为之生成一个对应的Class对象, 接着将会进入连接阶段, 连接阶段将会负责把类的二进制数据合并到JRE中. 类的连接分为三个阶段:
(1)验证: 验证阶段用于检验被加载的类是否具有正确的内部结构, 并和其他类协调一致.
(2)准备: 类准备阶段则负责为类的静态属性分配内存, 并设置默认初始值.
(3)解析: 将类的二进制数据中的符号引用替换成直接引用.
4.类的初始化
JVM初始化一个类包含如下几个步骤:
(1)假如这个类还没有被加载和连接, 程序先加载并连接该类.
(2)假如该类的直接父类还没有被初始化, 则先初始化其直接父类.
(3)假如类中有初始化语句, 则系统依次执行这些初始化语句.
<***>当程序主动使用任何一个类时, 系统会保证该类以及所有父类(包括直接父类和间接父类)都会被初始化.
5.类初始化的时机
当Java程序首次通过以下6种方式来使用某个类或接口时, 系统会初始化该类或接口:
(1)创建类的实例, 为某个类创建实例的方式包括使用new关键字来创建实例, 通过反射来创建实例, 通过反序列化的方式来创建实例.
(2)调用某个类的静态方法.
(3)访问某个类或接口的静态属性, 或者为该静态属性赋值.
(4)使用反射方式来强制创建某个类或者接口对应的java.lang.Class对象.
(5)初始化某个类的子类, 该子类的所有父类都会被初始化.
(6)直接使用java.exe命令来运行某个主类, 当运行某个主类时, 程序会先初始化该主类.
二. 类的反射
1.什么是反射?
反射就是通过获取class字节码文件对象/Class类对象, 来获取字节码文件对象中的成员变量, 构造方法, 和成员方法.
Field: 简称成员变量 (Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。 反射的字段可能是一个类(静态)字段或实例字段。)
Constructor:简称构造方法:提供关于类的单个构造方法的信息以及对它的访问权限.
Method:简称成员方法:类或接口上单独某个方法(以及如何访问该方法)的信息.
2.面试题: 如何获取class字节码文件对象/Class的类对象?
三种方式:(1)Object中的getClass()方法
(2)某个类的静态class属性来获取该类的Class对象
(3)Class类中的方法:forName(String className)
forName("类路径")该字符串的参数是某个类的全限定类名
开发中使用第三种方式,forName方法中的参数是一个String类型,以后可以用字符串类型数据作为配置文件!
3.通过Class对象获取构造方法并使用
获取指定的构造方法
获取私有的构造方法,并通过私有构造方法的对象来创建实例
使用getDeclaredConstructor()方法同样可以获取其他访问权限的构造方法,并创建实例.
4.通过反射获取成员变量,并使用
5.通过反射获取成员方法,并使用