类加载机制--浅谈

一、定义:

    类加载(Class Loading)是一种机制,他描述的是将字节码以文件形式加载到内存再经过连接、初始化后,最终形成可以被虚拟机直接使用的Java类型地过程。

    Class Loading 包含了加载(Loading)、连接(Linking)、初始化(Initialization)三大部分,其中Linking又包含了三个部分:校验(Verification)、准备  (Preparation)、解析(Resolution)。而一个类的生命周期只是在Class Loader的基础上多了:使用(Using),卸载(Unloading)两部分。

Class Loaders的组成:

二、加载阶段

虚拟机需要完成以下3件事情:

1)通过一个类的全限定名来获取定义此类的二进制字节流。

2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

注意:

    1.JVM在加载数组的时候加载的仅仅是数组的类型类(例如String[] 加载器只会加载String这个类型类),而数组的创建则由JVM直接完成。

这里我们多问几个为什么:
    2. JVM为什么只加载数组的类型类:
我认为JVM这样做的目的主要是为了节省时间,我们知道数组里面装的都是同一种类型的元素,JVM没必要将一个重复的内容加载多次浪费时间。
    3. N维数组怎么加载:
如果是N维数组,类加载器会从最外层开始一层一层的递归加载,直到加载到非数组类型为止。
    4. 引用类型与基本类型加载起来会不会有区别:
其实基本类型早已经在javac阶段装箱成封装对象了,例如int会被装箱成Integer,long装箱成Long等等,所以是没有区别的。

三、验证

      验证是连接阶段的第一步,这一阶段目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全。

      虚拟机规范对这个阶段的限制和指导非常笼统,仅仅说了一句如果验证到输入的字节流不符合Class文件的存储格式,就抛出一个java.lang.VerifyError异常或者其子类异常。具体应当检查哪些方面,如何检查,何时检查,都没有强制要求或明确说明,所以不同的虚拟机对验证的实现可能会有所不同,但大致上都会完场下面四个阶段的检验过程:文件格式验证、元数据验证、字节码验证和符号引用验证。

        是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。但从整体上看,验证阶段大致上会完成下面4个阶段的检验动作:文件格式验证、元数据验证、字节码验证、符号引用验证。

  1. 文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以魔术0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。
  2. 元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。
  3. 字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
  4. 符号引用验证:确保解析动作能正确执行。

四、准备阶段

       是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。

       这个阶段中有两个容易产生混淆的概念需要强调一下,首先,这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在Java堆中。其次,这里所说的初始值“通常情况”下是数据类型的零值,假设一个类变量的定义为:

public static int value=123;

那变量value在准备阶段过后的初始值为0而不是123,因为这时候尚未开始执行任何Java方法,而把value赋值为123的putstatic指令是程序被编译后,存放于类构造器<clinit>()方法之中,所以把value赋值为123的动作将在初始化阶段才会执行。表7-1列出了Java中所有基本数据类型的零值。

假设上面类变量value的定义变为:public static final int value=123;

编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为123。

五、解析阶段

是虚拟机将常量池内的符号引用替换为直接引用的过程

六、初始化

在连接的准备阶段,类变量已赋过一次系统要求的初始值,而在初始化阶段,则是根据程序员自己写的逻辑去初始化类变量和其他资源,举个例子如下:

    public static int value1  = 5;public static int value2  = 6;static{value2 = 66;}

在准备阶段value1和value2都等于0;

在初始化阶段value1和value2分别等于5和66;

  • 所有类变量(类变量是声明在class内,method之外,且使用static修饰的变量)初始化语句和静态代码块都会在编译时被前端编译器放在收集器里头,存放到一个特殊的方法中,这个方法就是<clinit>方法,即类/接口初始化方法,该方法只能在类加载的过程中由JVM调用;
  • 编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块中只能访问到定义在静态语句块之前的变量;
  • 如果超类还没有被初始化,那么优先对超类初始化,但在<clinit>方法内部不会显示调用超类的<clinit>方法,由JVM负责保证一个类的<clinit>方法执行之前,它的超类<clinit>方法已经被执行。
  • JVM必须确保一个类在初始化的过程中,如果是多线程需要同时初始化它,仅仅只能允许其中一个线程对其执行初始化操作,其余线程必须等待,只有在活动线程执行完对类的初始化操作之后,才会通知正在等待的其他线程。(所以可以利用静态内部类实现线程安全的单例模式)
  • 如果一个类没有声明任何的类变量,也没有静态代码块,那么可以没有类<clinit>方法;

何时触发初始化

  1. 为一个类型创建一个新的对象实例时(比如new、反射、序列化)
  2. 调用一个类型的静态方法时(即在字节码中执行invokestatic指令)
  3. 调用一个类型或接口的静态字段,或者对这些静态字段执行赋值操作时(即在字节码中,执行getstatic或者putstatic指令),不过用final修饰的静态字段除外,它被初始化为一个编译时常量表达式
  4. 调用JavaAPI中的反射方法时(比如调用java.lang.Class中的方法,或者java.lang.reflect包中其他类的方法)
  5. 初始化一个类的派生类时(Java虚拟机规范明确要求初始化一个类时,它的超类必须提前完成初始化操作,接口例外)
  6. JVM启动包含main方法的启动类时。

七、系统的类加载器

类加载器名称

加载的范围

启动类加载器

Bootstrap ClassLoader

存放在<JAVA_HOME>\lib目录中的,并且是虚拟机 识别的类库加载到虚拟机内存中

扩展类加载器 Extension ClassLoader

存放在<JAVA_HOME>\lib\ext目录中的所有类库, 开发者可以直接使用;

应用程序加载器 Application ClassLoader

加载用户类路径上指定的类库,开发者可以直 接使用,一般情况下这个就是程序中默认的类 加载器;

八、双亲委派机制

        某个特定的类加载器在接到加载类的请求 时,首先将加载任务委托给父类加载器, 依次递归,如果父类加载器可以完成类加 载任务,就成功返回;只有父类加载器无 法完成此加载任务时,才自己去加载

        双亲委派模型好处:Java类随着它的类加载器一起具备了带 有优先级的层次关系,保证java程序稳 定运行

九、示例代码

public class SuperClazz {public SuperClazz(){System.out.println("我是父类构造方法");}static {System.out.println("我是父类静态代码块");}public static int value = 123;public static final String STR = "hello world";public static final int WHAT = value;
}public class SonClazz extends SuperClazz {public SonClazz(){System.out.println("我是子类构造方法");}static {System.out.println("我是子类静态代码块");}
}
public class DemoTest {
public static void main(String args[]){ /*
        System.out.println(SonClazz.value);
输出结果:
我是父类静态代码块
123
结论:对于静态字段,只有直接定义这个字段的类,才能被初始化。
*/
/*
SuperClazz[] aa = new SuperClazz[10];
输出结果:(什么也没有输出)
结论:只是声明了一个数组形式的变量,类没有初始化
*/

/*
System.out.println(SonClazz.STR);
输出结果:hello world
结论:编译期的传播优化,因为是常量,所以就会直接编译到了运行的类里面,就不会再去定义的类里面找了
,STR还是在常量池里面的;
*/

     /**

      我是父类静态代码块
      123

    */
//System.out.println(SonClazz.WHAT);


}
 
public class DemoTest2 {static{i=0;System.out.println(i);//这句编译器会报错:Cannot reference a field before it is defined(非法向前应用)
    }static int i=1;
}
public class DemoTest2 {static{i=2;
//      System.out.println(i);
    }static int i=1;public static void main(String args[]){System.out.println(i);}
}输出结果:1

 

转载于:https://www.cnblogs.com/lys-lyy/p/10771751.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/569491.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第二次团队作业

团队序号&#xff1a;10 团队名称&#xff1a;春天花花幼儿 团队码云地址&#xff1a;https://gitee.com/hxhdemayun/hxh.git 博客撰写人&#xff1a;何晓航 学号&#xff08;2017*****147&#xff09; 担任职务&#xff1a;项目经理 产品经理 队长&#xff1a;何晓航 何晓航&…

修改主机名(/etc/hostname和/etc/hosts区别)

ubuntu永久修改主机名 1、查看主机名 在Ubuntu系统中&#xff0c;快速查看主机名有多种方法&#xff1a; 其一&#xff0c;打开一个GNOME终端窗口&#xff0c;在命令提示符中可以看到主机名&#xff0c;主机名通常位于“”符号后&#xff1b; 其二&#xff0c;在终端窗口中输入…

openstack Nova日志相关

简介 instance 从创建到删除的整个生命周期都是由 Nova 管理的。 后面各小节我们以 instance 生命周期中的不同操作场景为例&#xff0c;详细分析 Nova 不同组件如何协调工作&#xff0c;并通过日志分析加深大家对 Nova 的理解。 在研究 Nova 各个操作之前&#xff0c;我们先…

Hadoop Mapreduce 调优

转载于:https://www.cnblogs.com/pickKnow/p/10783304.html

从深圳到南阳-13天单骑3000里回家记

离人单骑披暮霭&#xff0c;谁家炊烟漫黄昏。 ——生活不止眼前的苟且&#xff0c;还有诗和远方的田野。 远方总是在召唤。 当城市的冷暖变化不再敏感&#xff0c;当漂泊的心终于疲倦得不愿坚持&#xff0c;当孩子日益叛逆&#xff0c;当父母需要相守。 当对职场早已厌倦&#…

Python安装Matplotlib,wordcloud,jieba第三方库

以下安装都在cmd窗口下操作 1.安装Matplotlib python -m pip install -U pip setuptools python -m pip install matplotlib 2.安装wordcloud pip install wordcloud 3.安装jieba pip install jieba

Git Bash中npm配置,加速下载等作用

每输入一行&#xff0c;回车&#xff0c;没有任何提示&#xff0c;说明操作成功 1. npm config set registry https://registry.npm.taobao.org 2.npm config set loglevel http 3. npm config set progress false 4.npm的配置被存储在 ~/.npmrc&#xff0c;可以随时改

Git Bash推送GitHub不成功---密钥设置

可能出现问题&#xff1a;输入 git push -u origin master之后&#xff0c;会出现对话框&#xff0c;输入yes&#xff0c;会发现连接不上&#xff0c;那么在GitHub执行下面操作 我们用Git Bash连接GitHub&#xff0c;若连接不成功&#xff0c;可用下述方法试试&#xff1a; 1…

在Windows中为文件添加“可执行”权限(chmod +x 文件名 不起作用)

我们想为Windows中某文件添加可执行权限&#xff0c;原本想用 chmod x 文件名 命令&#xff0c;但发现不起作用&#xff0c; 于是&#xff0c;尝试下面方法 在demo.txt文件中&#xff0c;打开&#xff0c;第一行添加语句 #!/bin/bash 保存后&#xff0c;查看&#xff0c;已…

CSS 横向导航栏(由竖向改成横向 float)

float元素默认会收缩 div块级元素&#xff0c;默认从上往下流 如何让导航栏有竖排→横排 给每一块加上 float&#xff1a;left&#xff1b; 注意事项&#xff1a;以防出bug&#xff0c;在加了float块的父级&#xff0c;加上伪类&#xff1a;clearfix&#xff0c;具体写法如下…

float:left后,导航栏不左浮解决

float:left 导航栏左浮&#xff0c;但加入 width&#xff1a;50%后&#xff0c;本想达到下面效果&#xff1a; 但是&#xff0c;所有元素成一列&#xff0c;不左浮了 原因&#xff1a;可能是你加了边框&#xff0c;边框占像素&#xff0c;所以相当于把剩余的50%“挤下来了” …

单词统计

题目&#xff1a; 第0步&#xff1a;输出某个英文文本文件中 26 字母出现的频率&#xff0c;由高到低排列&#xff0c;并显示字母出现的百分比&#xff0c;精确到小数点后面两位。 第1步&#xff1a;输出单个文件中的前 N 个最常出现的英语单词。作用&#xff1a;一个用于统计文…

轻松自动化---selenium-webdriver(python) (四)

https://www.cnblogs.com/fnng/p/3190966.html http://www.testclass.net/ 测试教程网&#xff0c;专业的selenium 学习网站。 本节要解决的问题&#xff1a; 如何定位一组元素&#xff1f; 场景 从上一节的例子中可以看出&#xff0c;webdriver可以很方便的使用findElement方…

如何用CSS画一个三角形

border-left-color: border-top-width:中心距顶部距离 .userCard .welcome .triangle{ border: 8px solid transparent;width: 0px;height: 0px;border-left-color: #E8676B;border-top-width: 0; } 结果 → 这篇博客很清楚&#xff0c;可借助参考&#xff1a;https://…

CSS hr修改样式

hr 默认样式 若加上这样CSS hr{height: 0;border: none;border-top: 1px solid red; } 会变为

scrapy框架的日志等级和请求传参

Scrapy的日志等级 - 在使用scrapy crawl spiderFileName运行程序时&#xff0c;在终端里打印输出的就是scrapy的日志信息。- 日志信息的种类&#xff1a;ERROR &#xff1a; 一般错误WARNING : 警告INFO : 一般的信息DEBUG &#xff1a; 调试信息- 设置日志信息指定输出&#x…

12-order by和group by 原理和优化 sort by 倒叙

原理和优化 groupBy分组&#xff1f;会造成一个数据倾斜 1.解决方案&#xff1a;将输入在map端进行部分的打乱重分 set hive.groupby.skewindatatrue; 2.在map到reduce端的时候设置combiner进行合并 set hive.map.aggrtrue; 3.在combiner进行合并的时候要知道数据量的大小&…

DOM相关(主要是var和let的区别用法)

一、1.节点的类型有七种&#xff0c;分别是&#xff1a;Document&#xff0c;DocumentType&#xff0c;Element&#xff0c;Attribute&#xff0c;Text&#xff0c;Comment&#xff0c;DocumentFragment 2.DOM树的根节点是&#xff1a;html 3.元素Element的NodeType值为&…

JOIN三个表格

表格一 表格二 表格三 SQL语句为 SELECT * FROM movie JOIN casting ON movie.idcasting.movieid     JOIN actor ON casting.actoridactor.id(要注意join 的格式) 最终结果展示在最下面 idtitleyrdirectorbudgetgrossmovieidactoridordidname1001710 Rillington Place19…

深度学习入门|第5章 误差反向传播法(二)

误差反向传播法 前言 此为本人学习《深度学习入门》的学习笔记 四、简单层的实现 本节将用 Python 实现前面的购买苹果的例子。这里&#xff0c;我们把要实现的计算图的乘法节点称为“乘法层”&#xff08;MulLayer&#xff09;&#xff0c;加法节点称为“加法层”&#xff08;…