过程:当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载、连接、初始化三个步骤来对该类进行初始化,有时候称为类加载(类初始化)
 
类加载 定义:类加载 指的是将类的class文件读入内存,并为之创建一个java.lang.Class对象
 
类也是一种对象:每个类是一批具有相同特征的对象的抽象,而系统中的所有类,它们实际上也是对象,它们都是java.lang.Class的实例
 
类加载器:类的加载由类加载器完成,JVM提供的类加载器称为系统类加载器,开发者可以通过继承ClassLoader基类来创建自己的类加载器
 
使用不同的类加载器,可以从不同的来源加载类的二进制数据,通常有如下几种来源:
    (1)从本地文件系统加载class文件
    (2)从JAR包中加载class文件
    (3)通过网络加载class文件
    (4)把一个java源文件动态编译、并执行加载
 
 
类连接 定义:连接阶段将会负责把类的二进制数据合并到JRE中,又可分为如下三个阶段:
    (1)验证:检验被加载的类是否有正确的内部结构,并和其它类协调一致
    (2)准备:为类的静态属性分配内存,并设置默认初始值
    (3)解析:将类的二进制数据中的符号引用替换成直接引用 ???  http://zhanjia.iteye.com/blog/1877236  http://m.oschina.net/blog/144133
 
类的初始化 定义:虚拟机对类进行初始化,主要是对静态属性进行初始化,有两种方式:
    (1)声明静态属性时指定初始值
    (2)使用静态初始化块为静态属性执行初始值
 1 public class Test {
2 static {
3 b = 6;
4 System.out.println("-----------");
5 }
6 static int a = 9;
7 static int b = 9;
8
9 public static void main(String[] args) {
10 System.out.println("b = " + Test.b); //结果为9
11 }
12 }
JVM初始化一个类的步骤:
    (1)假如这个类还没有被加载和连接,程序先加载和连接该类
    (2)假如该类的直接父类没有被初始化,则先初始化其直接父类(如果直接父类也有父类,会一直重复(1)(2)(3))
    (3)假如类中有初始化语句,则系统依次执行这些初始化语句
因此,JVM最先初始化的总是java.lang.Object类,当程序主动使用任何一个类时,系统会保证该类以及所有父类(包括直接父类和间接父类)都会被初始化
 
 
何时初始化类:当使用下面6种方式使用   
    (1)创建类的实例:包括用new、反射、反序列化来创建
    (2)调用某个类的静态方法    
    (3)访问某个类或接口的静态属性,或为该静态属性赋值
    (4)使用反射来强制创建某个类或接口对应的java.lang.Class对象。例如,代码Class.forName("Person"),如果系统还未初始化Person类,则这行代码会导致该Person类被初始化,并返回Person类对应的java.lang.Class对象
    (5)初始化某个类的子类
    (6)直接使用java.exe来运行某个主类,当运行某个主类时,程序会先初始化该主类
 
特殊说明1:对于一个final类型的静态属性
    (1)编译时常量:如果它的值在编译时就可以得到,系统使用时会认为是对该类的被动使用,所以不会导致该类的初始化
    (2)运行时常量:如果它的值必须在运行时才可以得到,会导致该类的初始化
 
 1 class MyTest{
2 static {
3 System.out.println("静态初始化块");
4 }
5
6 static final String compileCon = "编译时常量";
7 static final String runningCon = System.currentTimeMillis() + "";
8 }
9
10 public class TestCompileConstant {
11 public static void main(String[] args) {
12 System.out.println(MyTest.compileCon);
13 System.out.println("*****************");
14 System.out.println(MyTest.runningCon);
15 }
16 }
 
特殊说明2:当使用ClassLoader类的loadClass()方法加载某个类时,该方法只是加载该类,并不会执行该类的初始化;当使用Class类的forName()静态方法才会导致强制初始化该类
 
 1 class MyTest1{
2 static {
3 System.out.println("MyTest1类的静态初始化块");
4 }
5 }
6
7 public class ClassLoaderTest{
8 public static void main(String[] args) throws ClassNotFoundException{
9 ClassLoader c1 = ClassLoader.getSystemClassLoader();
10 c1.loadClass("MyTest1"); //该语句仅是加载MyTest1类,并不执行该类的初始化
11 System.out.println("系统加载MyTest1类");
12 Class.forName("MyTest1"); //当使用Class的forName()静态方法才会导致该类的强制初始化
13 }
14 }
 
 
 
类加载器简介:
 
1、一旦一个类被载入JVM中,同一个类就不会再被载入了。
 
那么 如何标识一个类:(全限定类名, 加载器)  或者叫做 (类名, 包名, 加载器),如果在pg包中,有一个名为Person的类,被类加载器KclassLoader的实例k1负责加载,则该Person类对应的Class对象在JVM中表示为(Person,pg,k1);这意味着两个类加载器加载的同名类:(Person,pg,k1)、(Person,pg,k2)是完全不同,互不兼容的。
 
 
2、当JVM启动时,会形成由三个类加载器组成的初始类加载器层次结构:
 
    (1)根类加载器(Bootstrap ClassLoader):加载jdk/jre/lib/rt.jar等系统核心类库——比较特殊,它并不是java.lang.ClassLoader的子类,而是由JVM自身实现的
    (2)扩展类加载器(Extension ClassLoader):它负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统熟悉指定的目录)中JAR的类包。——通过这种方式,我们可以为Java扩展核心类以外的新功能,只要把我们自己开发的类包打成JAR文件,然后放入JAVA_HOME/jre/lib/ext路径即可
    (3)系统(应用)类加载器(System ClassLoader):它负责在JVM启动时,加载来自命令java中的-classpath选项或java.class.path系统属性,或者CLASSPATH环境变量所指定的JAR包和类路径——通过ClassLoader的静态方法getSystemClassLoader()获取该类系统类加载器
 
JVM的类加载机制主要有如下三种机制:
1、全盘负责:当一个类加载器负责加载某个Class的时候,该Class所依赖的和引用的其它Class也将由该类加载器负责载入,除非使用另一个类加载器来载入
2、父类委托:先让parent(父)类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
3、缓存机制:缓存机制会保证所有被加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器会先从缓存中搜该Class,只有缓存中不存在该        Class对象时,系统才会重新读取该类对应的二进制数据,并将其转换成Class对象,并存入cache。——这就是为什么我们修改了Class后,程序必须重新启动JVM,程序所做的修改才会生效的原因
 
例1:
 1 import java.net.URL;
2
3 public class BootstrapTest {
4 public static void main(String[] args) {
5 //获取根类加载器所加载的全部URL数组
6 URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
7 //遍历、输出根类加载器加载的全部URL
8 for (int i=0; i<urls.length; i++) {
9 System.out.println(urls[i].toExternalForm());
10 }
11 }
12 }
 
例2:
 1 import java.net.URL;
2 import java.util.Enumeration;
3 import java.io.*;
4
5 public class ClassLoaderProp {
6 public static void main(String[] args) throws IOException {
7 ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
8 System.out.println("系统类加载器: " + systemLoader);
9
10 //获取系统类加载器的加载路径,通常由classpath环境变量指定
11 //如果操作系统没有指定classpath变量,默认以当前路径作为系统类加载器的加载路径
12 Enumeration<URL> em1 = systemLoader.getResources("");
13 while (em1.hasMoreElements()) {
14 System.out.println(em1.nextElement());
15 }
16
17 //获取系统类加载器的父类加载器——应该得到扩展类加载器
18 ClassLoader extensionLader = systemLoader.getParent();
19 System.out.println("扩展类加载器:" + extensionLader);
20 System.out.println("扩展类加载器的加载路径:" + System.getProperty("java.ext.dirs"));
21 System.out.println("扩展类加载器的parent:" + extensionLader.getParent());
22 }
23 }
 
几点结论:
1、系统类加载器的路径是classpath指定的路径
2、扩展类加载器的路径:是JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统熟悉指定的目录
3、扩展类加载器的父加载器是null,这是因为根加载器没有继承ClassLoader抽象类,所以此处返回null;但根类加载器确实是扩展类加载器的父类加载器
4、系统类加载器是AppClassLoader的实例,扩展类加载器是ExtClassLoader的实例,实际上这两个类都是URLClassLoader的实例

继承关系:

java.lang.Object

--- java.lang.ClassLoader
              --- java.security.SecureClassLoader
                      ---  java.net.URLClassLoader
                            --- sun.misc.Launcher$ExtClassLoader

java.lang.Object

--- java.lang.ClassLoader
              --- java.security.SecureClassLoader
                      ---  java.net.URLClassLoader
                            --- sun.misc.Launcher$AppClassLoader

 
 
类加载体系的目标:
1、类能够延迟加载
2、加载后能够有效运行
3、类之间能够隔离
4、类占用的资源能够回收

JAVA类的加载(1) ——类的加载及类加载器介绍的更多相关文章

  1. 【转】怎么解决java.lang.NoClassDefFoundError错误 ,以及类的加载机制

    转自http://blog.csdn.net/jamesjxin/article/details/46606307 前言 在日常Java开发中,我们经常碰到java.lang.NoClassDefFo ...

  2. jvm(1)类的加载(二)(自定义类加载器)

    [深入Java虚拟机]之四:类加载机制 1,从Java虚拟机的角度,只存在两种不同的类加载器: 1,启动类加载器:它使用C++实现(这里仅限于Hotspot,也就是JDK1.5之后默认的虚拟机,有其他 ...

  3. JVM性能优化--类加载器,手动实现类的热加载

    一.类加载的机制的层次结构 每个编写的".java"拓展名类文件都存储着需要执行的程序逻辑,这些".java"文件经过Java编译器编译成拓展名为". ...

  4. Java的类加载器都有哪些,每个类加载器都有加载那些类,什么是双亲委派模型,是做什么的?

    类加载器按照层次,从顶层到底层,分为以下三种: (1)启动类加载器(Bootstrap ClassLoader) 这个类加载器负责将存放在JAVA_HOME/lib下的,或者被-Xbootclassp ...

  5. 第42天学习打卡(Class类 Class类的常用方法 内存分析 类的加载过程 类加载器 反射操作泛型 反射操作注解)

    Class类 对象照镜子后得到的信息:某个类的属性.方法和构造器.某个类到底实现了哪些接口.对于每个类而言,JRE都为其保留一个不变的Class类型的对象.一个Class对象包含了特定某个结构(cla ...

  6. Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架

    类加载器 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader 类加载器也是Jav ...

  7. JAVA基础加强(张孝祥)_类加载器、分析代理类的作用与原理及AOP概念、分析JVM动态生成的类、实现类似Spring的可配置的AOP框架

    1.类加载器 ·简要介绍什么是类加载器,和类加载器的作用 ·Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader ...

  8. JVM自定义类加载器加载指定classPath下的所有class及jar

    一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...

  9. jvm(1)类加载(一)(加载过程,双亲加载)

    JVM类加载器机制与类加载过程 jvm虚拟机的种类: Hotspot(Oracle)(基本上都是在说这个) J9, JikesRVM(IBM) Zulu, Zing (Azul) Launcher是一 ...

  10. 深入理解JVM-类加载及类加载器

    深入理解JVM 2020年02月06日22:43:09 - 记录学习过程 终于开始了.在学习这个之前,看了zhanglong老师的 java 8 和springboot 迫不及待了.先开始吧. 写在前 ...

随机推荐

  1. switch写法详解

    我们在开发项目中经常遇到对数据的判断进行相应的逻辑(if..else  ,三元运算等),Switch 语句用来选择多个需要执行的代码块 ,一定程度上简化了if....else 1. 语法 switch ...

  2. Vortex Indicator 构建交易策略

    更多精彩内容,欢迎关注公众号:数量技术宅,也可添加技术宅个人微信号:sljsz01,与我交流. 今天的文章,我们将为大家介绍一个与DMI(Directional Movement Index)类似,判 ...

  3. Mysql报错:Specified key was too long; max key length is 767 bytes

    1.show variables like 'innodb_large_prefix'; show variables like 'innodb_file_format'; 修改为如下配置: set ...

  4. 压缩 js 代码就用 terser

    webapck 中提供了压缩 js 代码的方式,可以移除无用代码.替换变量名等,减少编译后文件体积,提升加载速度. 不同mode 在 webpack 配置文件 webpack.config.js 中通 ...

  5. 用python用户注册和短信验证码逻辑实现案例

    一.写代码前分析(逻辑分析OK了才可以顺利成章的敲代码): A.用户发送请求 1.注册账号(用户名不能重复)--按照需求进行判断 2.短信验证码(有效期5分钟)--对短信验证码进行保存 B.用户注册. ...

  6. aspnetcore 注册中心 consul

    consul启动 . http://192.168.1.6:8500/ #以server方式启动,UI可以访问,boot引导自己选为leader,网段内PC可访问 consul agent -serv ...

  7. [Lua][Love Engine] 有效碰撞处理の类别与位掩码 | fixture:setFilterData

    有效的碰撞处理 只用IF判断 假设在一个物理世界,不希望两个同类实体发生碰撞,那么 local begin_contact_callback = function(fixture_a, fixture ...

  8. SSM登录操作

    1.编写实体类 略 2. 写mapper映射文件 通过名字查询 通过ID主键查询... 略 写dao CRUD相关抽象方法 List<Student> getAll(); Student ...

  9. Android-JAR包的引用

    一.JAR的定义     JAR文件(Java归档,英语:Java Archive)是一种软件包文件格式,以ZIP格式构建,以.jar为文件扩展名,通常用于聚合大量的Java类文件.相关的元数据和资源 ...

  10. 如何分析 JVM 内存瓶颈浅谈

    背景: 当操作系统内存出现瓶颈时,我们便会重点排查那个应用占用内存过大.对于更深一步分析内存的使用,就进一步去了解内存结构,应用程序使用情况,以及内存如何分配.如何回收,这样你才能更好地确定内存的问题 ...