类的加载概述和加载时机
类的加载概述
- 类的加载是指: 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类的初始化.
加载: 指的是将Javac创建的class文件读入内存,并为之创建一个Class对象,任何类被使用时系统都会建立一个Class对象
连接: 包括三个步骤:
验证 是否有正确的内部结构,并和其它类协调一致.
准备 负责为类的静态成员分配内存,并设置默认初始化值.
解析 将类的二进制数据中的符号引用替换为直接引用,比如把常量的引用直接变成值.
- 初始化: 就是给成员变量赋值: 先默认值(比如int默认值为0)---->然后显式赋值(比如public inta = 10,这个**=**就是显式初始化)---->最后构造方法初始化(带参构造会给成员变量赋值这个都知道哈).
类的加载时机
创建类的实例时,例: Preson p = new Person().
访问类的静态变量,或者为静态变量赋值时
调用类的静态方法
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象.
初始化某个类的子类
直接使用java.exe命令来运行某个主类
类加载器的概述和分类
类加载器的概述
- 负责将.class文件加载到内存中,并为之生成对应的Class对象.
类加载器的分类
Bootstrap ClassLoader: 根类加载器
Extension ClassLoader: 扩展类加载器
System ClassLoader: 系统类加载器
类加载器的作用
根类加载器负责java核心类的加载,比如System,String等,在jre的lib目录下的rt.jar文件中.
扩展类加载器负责jre扩展目录中jar包的加载,在jre的lib目录下的ext目录下.
系统类加载器负责jvm启动时加载来自java命令的class文件
比如自定义类
,以及classpath环境变量所指定的jar包和类路径类初始化顺序
- 只有一个类的话,他的初始化顺序是这样子的
静态成员变量
静态代码块,例如: static{System.out.println(“静态代码块”)}
普通成员变量
普通代码块(就是静态代码块没有static关键字,直接就是
{内容}
)main方法
构造方法
反射
反射概述
java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的任意属性和方法,对于任意一个对象,都能够调用它的属性和方法
这种动态获取信息以及动态调用对象的方法和属性的功能称为java的反射机制
要想解剖一个类,必须先要获取到该类的字节码文件(字节码文件就是.class文件)对象,而解剖类使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象
获取Class文件对象的三种方式
Object类的getClass()方法,用于判断两个对象是否是同一个字节码文件,重写equals()方法时就有这么一个判断条件,调用格式: 对象名.getClass().
静态属性.class,即Person.class,用于当作静态方法的锁对象,调用格式: 类名.class
- 注意: 用.class创建Class对象时,不会自动初始化该Class对象(即不会加载静态代码块这些东西),Class的初始化在调用方法或者属性时候才会被执行
- Class类中静态方法forName(“全类名即包名.类名”),用于读取配置文件,例如我们读取jdbc的配置文件的时候,调用格式: 全类名.forName()
- 注意: 用这种方法创建成功Class对象后,就会立即对该对象进行初始化,即会马上执行静态代码块这些东西.
- 注意:
如果一个字段被static final修饰,我们称为’编译时常量’,在编译期就把它的值放到常量池里了,那么如果通过
.class
创建Class对象
的话,由于没有立即对Class对象进行初始化,然后该对象去调用常量也是不会对Class对象进行初始化的,也就是说不会调用static静态代码块这些东西.三种创建Class对象的方式,如果是针对同一个字节码文件的话,三个对象是相等的,因为一个字节码文件在内存中只会存在一个Class对象
我们写代码经历的不同的阶段以及在不同的阶段获取Class对象的方法如图:
案例演示获取Class对象的三种方式以及初始化顺序
public class Test4 {
public static final int a =10;
static int b = 20;
public static void main(String[] args) {
System.out.println("main函数加载了");
Test4 t = new Test4();
}
public static void get() {
System.out.println("这是静态方法");
}
static {
System.out.println("静态代码块被加载了");
}
public Test4() {
System.out.println("构造方法被加载了");
}
public int c = 30;
{
System.out.println("代码块加载了!");
}
}
class Test{
public static void main(String[] args) throws ClassNotFoundException {
Class c = Test4.class;
Test4 t = new Test4();
Class c1 = t.getClass();
Class c2 = Class.forName("Test4");
System.out.println("--------- ");
System.out.println(c == c2);//true
System.out.println(c1 == c);//true
System.out.println(c1 == c2);//true
}
}