类的加载笔记

类的加载笔记

、类的生命周期:

 

加载->验证->准备->解析->初始化

 

1、加载:把类的二进制.class文件读入内存,把它放在运行时的数据区的方法区内,然后再堆区创建这个类对应的Class对象。

 

1)类的加载:

从本地加载.class文件

从网络下载.class文件

.jar.rar文件中提取.class文件

等等。

 

2)类加载器:

1java虚拟机自带的类加载器,包括启动类加载器、扩展类加载器和系统类加载器

2)用户自定义的类加载器,它是java.lang.ClassLoader的子类

 

 

【注意】:一个类并不是在首次主动使用时才加载,Java虚拟机允许预先加载。

 

2、验证

保证加载的数据正确

3、准备

在准备阶段,虚拟机为类静态变量分配内存并设置默认值

4、解析

解析阶段,虚拟机把符号引用替换为直接引用、

5、初始化

为类的静态变量赋初值(声明时初始化或者在静态代码块中初始化;注意:final static表示常量,而且只能声明时赋值且必须赋值),初始化的过程包括:

1)如果类没有加载和连接,先加载和连接。

2)此类存在直接父类,那么先初始化父类(这保证主动使用此类时,此类和它的所有父类都初始化了)

3)有初始化语句(声明时初始化或者静态代码块中初始化),就依次执行这些语句。

 

【注意a】:只有程序主动使用一个类或者接口时,它才会初始化,主动使用包括:

1)创建类的对象(包括new创建、反射、clone()、反序列化)

2)调用类方法

3)访问类变量或者为其赋值

4)调用类的反射方法Class.forName("X"),会初始化X

5)初始化此类的子类

6)声明为启动类(即java XX类)

 

【注意b】:初始化一个接口时,不会初始化其父接口;初始化一个类时,不会初始化其实现接口

【注意c】:对于编译时常量,也不会初始化

【注意d】:只有类或者接口的静态属性和静态方法是在本类、接口中定义的,主动访问才会初始此类或者接口,否则只初始化父类或者实现接口。

【注意e】:ClassLoaderloadClass()方法不会初始化被调用的类,仅仅是加载

 

二、类的加载器

 

1、根加载器Bootstrap:加载虚拟机核心类库,如java.lang.*,它加载sun.boot.class.path指定的目录中的类。它没有父加载器,null表示。

 

2、扩展类加载器:它从java.ext,dirs属性指定的目录加载类或者从jre/lib/ext目录中加载类,它是java.lang.ClassLoader的子类,而且父加载器是根加载器

 

3、系统类加载器:从classpath目录中加载类,它是java.lang.ClassLoader的子类,还是用户自定义的类加载器的默认父加载器,而且其父加载器是扩展类加载器。通过ClassLoader.getSystemClassLoader()得到

 

4、用户自定义的类加载器,继承java.lang.ClassLoader类。可以通过Class对象.getClassLoader()获得此类的类加载器

 

【注意】:类加载器的父子关系并不是类的继承关系,一对父子类加载器可能都是加载类的实例对象。除了根加载器外,每个类加载器都有且只有唯一一个父类加载器

 

5Java中类的加载是父加载器委托机制

 

假设有两个自定的类加载器classLoader1classLoader2classLoader2classLoader1的父类对象,要求classLoader2加载一个类A,那么classLoader2尝试从自己的命名空间(就是这个类加载器及其父加载器所加载的类的集合,命名空间中不允许存在完整类名完全相同的两个类)中查找此类是否已经加载,如果已经加载,就返回;没有就交给classLoader1classLoader1又会向上传递给系统类加载器,后者又请求扩展类加载器加载,而它又会请求根加载器加载;如果根加载器加载成功就向下传递给classLoader2,否则又有子类加载,……,如果classLoader2的父加载器都不能加载,那么classLoader2尝试加载,不能加载则抛出ClassNotFoundException异常。

 

6、我们知道java中有四种访问级别,其中protected是包内和子类可见,默认级别是包内可见。如果我们定义一个类java.lang.MyClass,那么在MyClass中能访问java.lang.*核心库的默认级别成员吗吗?如果可以,那么就会出问题,知道核心甚至修改细节。实际上不可能访问的,因为java.lang.MyClass与系统核心库的类加载器不同,所以是无法访问的,这样更安全。

 

7、数组类的 Class 对象不是由类加载器创建的,而是由 Java 运行时根据需要自动创建。数组类的类加载器由 Class.getClassLoader() 返回,该加载器与其元素类型的类加载器是相同的;如果该元素类型是基本类型,则该数组类没有类加载器。

 

8、自定义的类加载器:

 

继承ClassLoader,指定父加载器(在构造方法调用父类的构造方法super()说明父加载器为系统加载器;调用super(null)表示父加载器为根加载器);覆盖findClass()方法(一般需要调用protected final Class<?> defineClass(String name,byte[] b,int off,int len)方法(defineClass 方法将一个 byte 数组转换为 Class 类的实例))。

 

 

 

【注意】:

1、如果被加载的类中使用了另一个类,那么这个类由谁加载?也是使用父加载器委托机制。

 

2、同一个运行时包的类可以互相引用的。

 

3、子加载器加载的类可以引用父加载器加载的类,反之不行。

 

4、如果两个类加载器无父子关系,那么它们命名空间的类不能互相引用的。

 

5、处于不同命名空间的类要互相引用,可以使用反射的方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值