类加载器

类加载流程图

类加载过程.jpg

执行的每一个class文件都需要加载,加载完成在方法区创建一个class文件的对象,记录class文件信息。

类加载的时机

其中加载阶段和连接阶段是交叉进行的,并不是加载完才开始连接 ,其中连接的解析过程和初始化过程也是交叉进行的。这个过
程不一定是完全执行完的,存在加载进来,但是没有初始化。

加载

1.通过一个类的全类名,获取类的的class文件二进制子节流
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据结构的访问入口

验证

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

准备

  准备阶段是为类的静态变量分配内存并将其初始化为默认值,这些内存都将在方法区中进行分配。
  准备阶段不分配类中的实例变量的内存,实例变量将会在对象实例化时随着对象一起分配在Java堆中。
 1. public static int value=1;
  在准备阶段value初始值为0 。在初始化阶段才会变为1。
 2.public static final int value =1;
  被final和static 修饰的基本类型和String不会再这个阶段赋值初始值
  编译时Javac将会为该常量生成ConstantValue属性,在类加载的准备阶段虚拟机便会根据ConstantValue为常量设置相应的
  值,如果该变量没有被final修饰,或者并非基本类型及字符串,则选择在类构造器中进行初始化。

解析

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

初始化

类初始化是类加载过程的最后一步,前面的类加载过程,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余
动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序代码。


初始化阶段是执行类构造器<clinit>()方法的过程。
<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}  块)中的语句合并产生的。
类初始化时机:
1、创建类的实例
2、访问类的静态变量(除常量【被final修辞的静态变量】原因:常量一种特殊的变量,因为编译器把他们当作值(value)而不
是域(field)来对待。
3、访问类的静态方法
4、反射如(Class.forName("my.xyz.Test"))
5、当初始化一个类时,发现其父类还未初始化,则先出发父类的初始化
6、虚拟机启动时,定义了main()方法的那个类先初始化

举例

<1>static 变量准备阶段初始值,初始化阶段赋值

 public static void main(String[] args) {
     CheckPrepareAssignmentTest checkPrepareAssignmentTest =new CheckPrepareAssignmentTest();
 }
}

class CheckPrepareAssignmentTest{
/*
  * 准备阶段会根据先后顺序给每个静态变量赋值,所有这个实例初始化为优先执行,再此之前后面的静态变量还没有没有赋值
  * 所以此时打印的字段应该是准备阶段赋予的初始值
  */
   private static CheckPrepareAssignmentTest checkPrepareAssignmentTest = new CheckPrepareAssignmentTest();
   private final static Integer a = 1;
   private final static int b = 1;
   private static int c = 1;

   public CheckPrepareAssignmentTest(){
       System.out.println(String.format("初始化方法 此时的 a = %s  b=%s  c=%s",a,b,c));
   }

}

CheckPrepareAssignmentTest 类中创建一个自身的静态变量,准备阶段会根据先后顺序给每个静态变量赋值,所有这个实例初始化为优先执行,再此之前后面的静态变量还没有没有赋值所以此时打印的字段应该是准备阶段赋予的初始值。

结果
初始化方法 此时的 a = null  b=1  c=0
初始化方法 此时的 a = 1  b=1  c=1



验证结论:
1.准备阶段会给静态变量赋值,包括static final 修饰的非基本类型和String
2.static final 修饰的基本类型或者String 会直接从ContantsValue中赋值,不会赋初始值(b)

<2>加载但是不一定初始化

public class StudyClassLoader
{
    public static void main(String[] args)
    {
        System.out.println(Children.a);
    }
}

class Father{
    public static int a = 1;
    static {
        System.out.println("Father static{} 执行");
    }
}

class Children extends Father{
    static {
        System.out.println("Children static{} 执行");
    }
}
结果
Father static{} 执行
1

  结论:
  1.调用父类的静态变量,本身不需要初始化
  2.Children类对象信息加载了,但是本身并没有初始化(初始化会打印Static{}里面的内容)

类加载器

BootStarp类加载器

    由c/c++语言编写,启动类加载器,并非继承ClassLoader(疑问:是否是因为如果是java编写      
    那么,谁又来加载它呢),基本上Jdk里面的核心类都是BootStarp类加载器加载的
public class ClassLoaderTest
{
    public static void main(String[] args)
    {
        URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
        for (URL e:urls){
            System.out.println(e.toExternalForm());
        }
    }
}
结果
file:/C:/Program%20Files/Java/jdk1.8.0_161/jre/lib/resources.jar
file:/C:/Program%20Files/Java/jdk1.8.0_161/jre/lib/rt.jar
file:/C:/Program%20Files/Java/jdk1.8.0_161/jre/lib/sunrsasign.jar
file:/C:/Program%20Files/Java/jdk1.8.0_161/jre/lib/jsse.jar
file:/C:/Program%20Files/Java/jdk1.8.0_161/jre/lib/jce.jar
file:/C:/Program%20Files/Java/jdk1.8.0_161/jre/lib/charsets.jar
file:/C:/Program%20Files/Java/jdk1.8.0_161/jre/lib/jfr.jar
file:/C:/Program%20Files/Java/jdk1.8.0_161/jre/classes


这些都是BootStarp类加载器加载的包路径

拓展类加载器(Extension ClassLoader)

  1.java语言编写 ,由sun.misc.Launcher$ExtClassLoader实现。
  2.派生于ClassLoader类
  3.从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载
    类库。如果用户创建的JAR放在此目录下,也会由拓展类加载器自动加载

  在源码中可知ExtClassLoader加载类的目录
   方法:sun.misc.Launcher.ExtClassLoader#getExtDirs
   核心代码:String var0 = System.getProperty("java.ext.dirs");

应用程序类加载器(系统类加载器,AppClassLoader)

1.java语言编写, 由sun.misc.Launcher$AppClassLoader实现。
2.派生于ClassLoader类
3.它负责加载环境变量classpath或系统属性 java.class.path指定路径下的类库
4.该类加载器是程序中默认的类加载器,一般来说,java应用的类都是由它来完成加载
5.通过ClassLoader.getSystemClassLoader()方法可以获取到该类加载器

自定义类加载器

1.隔离加载类
2.修改类加载的方式
3.拓展加载源
4.防止源码泄漏

这里没有研究

双亲委派机制

类加载器图.png

作用

1.避免类的重复加载,如上
2.保护程序安全,防止核心API被随意修改
启动类加载器可以抢在标准扩展类装载器之前去装载类,而标准扩展类装载器可以抢在类路径加载器之前去装载那个类,类路径
装载 器又可以抢在自定义类加载器之前去加载它。所以Java虚拟机先从最可信的Java核心API查找类型,这是为了防止不可靠
的类扮演被信任的类,试想一 下,网络上有个名叫java.lang.Integer的类,它是某个黑客为了想混进java.lang包所起的名字,
实际上里面含有恶意代码,但是这种 伎俩在双亲模式加载体系结构下是行不通的,因为网络类加载器在加载它的时候,它首先
调用双亲类加载器,这样一直向上委托,直到启动类加载器,而启动类加载 器在核心Java API里发现了这个名字的类,所以它
就直接加载Java核心API的java.lang.Integer类,然后将这个类返回,所以自始自终网络上的 java.lang.Integer的类是不
会被加载的。

3.保证核心API包的访问权限
但是如果这个移动代码不是去试图替换一个被信任的类(就是前面说的那种情况),而是想在一个被信任的包中插入一个全新
的类型,情况会怎样呢?比如一个名为 java.lang.Virus的类,经过双亲委托模式,最终类装载器试图从网络上下载这个类
,因为网络类装载器的双亲们都没有这个类(当然没有了,
因为 是病毒嘛)。假设成功下载了这个类,那你肯定会想,Virus和lang下的其他类痛在java.lang包下,暗示这个类是Java
API的一部分,那么是不是也拥有修改Java.lang包中数据的权
限呢?答案当然不是,因为要取得访问和修改java.lang包中的权 限,java.lang.Virus和java.lang下其他类必须是属于同一
个运行时包的,什么是运行时包?运行时包是指由同一个类装载器装载的、属 于同一个包的、多个类型的集合。考虑一下,
java.lang.Virus和java.lang其他类是同一个类装载器装载的吗?不是 的!java.lang.Virus是由网络类装载器装载的!

  自定义类:java.lang.Test(java.lang包需要访问权限,阻止我们用包名自定义类)



总结一句:就是会从最上面的类加载器开始加载,知道找到能加载该类的类加载器加载为止,有点像责任链模式
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容