文档章节

java-类加载机制

啃不动地大坚果
 啃不动地大坚果
发布于 2017/07/15 20:36
字数 1458
阅读 14
收藏 1

1.jdk安装时会有两套jre的原因
jdk的各种工具都是由java编写的 这些工具本身也需要运行环境 所以jdk下会自带一套jre
jdk的bin目录下的各种exe程序都很小 只是一个包装器 内部实质都是调用的jar(\lib\tools.jar)文件来实现的

2.多套jre时实际选用哪套jre
1)自己目录下的jre 2)父目录下的jre 3)windows注册表下的jre

3.类文件的载入
   java.exe
 > 找到jre(将类文件.class移交给jre的类装载器)
 > 类装载器载入基础类库(\lib\rt.jar)

4.预先载入与按需载入
一般基础类库会预先载入 应用的类会按需载入 即在实际调用时才载入
有时我们会需要显式的预先载入一些类
1)java.lang.Class.forName()
forName(String className) 
forName(String name, boolean initialize, ClassLoader loader)
initialize会指定是否执行static方法 默认true false的话会在实际new的时候在执行
loader是指定类加载器 默认使用调用者的类加载器
2)java.lang.ClassLoader.loadClass()
loadClass 与 initialize false时一样 不会执行static方法
3)URLClassLoader

5.类加载机制
BootstrapLoader > ExtClassLoader 设置parent为null
BootstrapLoader > AppClassLoader(System Loader) 设置parent为ExtClassLoader

BootstrapLoader的搜索路径为 系统参数sun.boot.class.path
除了加载rt.jar等 默认还会搜索jre/classes

ExtClassLoader的搜索路径为 系统参数java.ext.dirs
默认为 jre的\lib\ext

AppClassLoader的搜索路径为 系统参数java.class.path
顺序为 缺省情况下为"."(当前目录) -classpath(-cp)指定的路径 classpath指定的系统变量

6.双亲委托模型
1.类加载时会先请示其parent使用对应的搜索路径搜索 找不到的话则按照自己的搜索路径搜索
2.同一个加载器:类A引用到类B,则由类A的加载器去加载类B,保证引用到的类由同一个加载器加载。
3.实际应用中,经常需要破坏双亲委托 常用的方法是Thread.getContextClassLoader()方法
eg1: jre/classes/father.java 
     jre/classes/son.java 
     jre/lib/ext/father.java 
     则jre/classes/father.java和jre/classes/son.java会被加载
eg1: jre/classes/father.java 
     jre/lib/son.java 
     jre/lib/ext/father.java 
     则jre/classes/father.java会被加载 但jre/classes/son.java会NoClassFoundException
     因为jre/classes/father.java会被BootstrapLoader加载 BootstrapLoader不会搜索子加载器的路径 只会搜索自己的路径

7.虚拟机对类的加载
7-1.生命周期 加载 连接(验证 准备 解析) 初始化 使用 卸载
7-2.类初始化的场景
虚拟机规范定义了 有且只有 的四种定义
a.遇到new getstatic setstatic invokestatic这4条字节码指令时
b.当初始化子类时父类还未初始化 初始化父类(但对于接口 子接口初始化时并不会初始化父接口)
c.对类进行反射调用时 如果类未初始化 则会执行初始化
d.用户指定的带main方法的主类

场景1:
class A{
    static{
        System.out.println("A init");
    }
    public static val = 100;
}
class B extends A{
    static{
        System.out.println("B init");
    }
}
输出:A init
调用B.val并不会初始化子类 但会初始化父类 只有直接定义的类才会初始化

场景2:
B[] arrB = new B[10] 不会初始化B 实际上虚拟机会通过newarray字节码命令生成B的数组类型

场景3:
class A{
    static{
        System.out.println("A init");
    }
    public final static val = 100;
}

此时不会初始化A 因为final static会被编译到实际调用类的常量池 A与实际调用类在编译后就没有关系了

7-3.类的加载过程
1)加载
  a.加载二进制流信息
  b.将二进制的静态存储信息转化为方法区中的运行时数据结构
  c.在java堆中生成Class对象 作为方法区数据的访问入口
2)验证
3)准备
  a.正式为static变量分配内存 设置变量初始值
    public static int value = 123;
    这里的初始值并不是123 而是0 实际的123赋值操作会被分解到类构造器<clinit>方法中 
    public static final int value = 123;
    这里的初始值并是123 常量的值会在准备阶段就设置好
4)解析
将符号引用替换为直接引用
5)初始化
a.即执行<clinit>的过程
  clinit中的方法是由编译器按照源码中出现的顺序对static变量和方法块收集而成
  因此 静态语句可以正常访问和赋值之前定义的语句 但只能赋值之后出现的静态变量 不能访问之后出现的静态变量(在编译期就会报错的)
  场景1:编译正确
      private static int a =1;
      private static int b =a;
     --准备
      a=0;
      b=0;
     --初始化
      a=1;
      b=a;
  场景2:编译错误
      private static int b =a;//不能访问
      private static int a =1;
  场景3:编译正确
      static{
          a=2;//可以赋值
      }
      private static int a =1;
      --准备
      a=0;
      --初始化
      a=2;
      a=1;
b.虚拟机会保证父类的<clinit>的过程在子类之前已经执行完成
  因此父类的静态方法会优先于子类执行
  但是 接口中的<clinit>不需要先执行父类的<clinit>
c.如果类中没有静态语句块 也没有变量赋值操作则不会有cinit操作
d.虚拟机会保证<clinit>的阻塞执行 如果同时有多个线程去初始化一个类
则其他线程都要阻塞 <clinit>中的耗时操作会造成严重阻塞

6)类的相等比较(equals instanceof等)
只有在类是由同一个类加载器加载的时候 类的相等比较才有意义
不同类加载器加载的同一个类 instanceof并不相等

© 著作权归作者所有

上一篇: MyBatis-基本语法
下一篇: git-git基本使用
啃不动地大坚果
粉丝 6
博文 120
码字总数 249840
作品 0
其它
程序员
私信 提问
Java Classloader机制解析

做Java开发,对于ClassLoader的机制是必须要熟悉的基础知识,本文针对Java ClassLoader的机制做一个简要的总结。因为不同的JVM的实现不同,本文所描述的内容均只限于Hotspot Jvm. 本文将会从...

aminqiao
2014/05/09
24K
2
浅谈java classloader

本文由作者张远道授权网易云社区发布。 类加载器三杰 jvm有三类classloader,分别是bootstrap classloader,extended classloader以及system classloader。 bootstrap classloader是系统在启动...

网易云
2018/12/14
0
0
ClassLoader加载Class的过程 解析

ClassLoader即类加载器,负责将 .class 文件(可能在磁盘上, 也可能在网络上) 加载到内存中, 并为之生成对应的 java.lang.Class 对象,当 JVM 启动时,会形成由三个类加载器组成的初始类加载器...

phacks
2015/08/19
62
0
Java核心机制:反射机制的原理及应用方法

一、java的核心机制 java有两种核心机制:java虚拟机(JavaVirtual Machine)与垃圾收集机制(Garbage collection): 1、Java虚拟机:是运行所有Java程序的抽象计算机,是Java语言的运行环境,在...

Java架构资源分享
2018/11/25
163
0
Java代码编译和执行的整个过程

Java代码编译是由Java源码编译器来完成,流程图如下所示: Java字节码的执行是由JVM执行引擎来完成,流程图如下所示: Java代码编译和执行的整个过程包含了以下三个重要的机制: Java源码编译...

xiejunbo
2016/02/11
1K
1

没有更多内容

加载失败,请刷新页面

加载更多

《Designing.Data-Intensive.Applications》笔记 四

第九章 一致性与共识 分布式系统最重要的的抽象之一是共识(consensus):让所有的节点对某件事达成一致。 最终一致性(eventual consistency)只提供较弱的保证,需要探索更高的一致性保证(stro...

丰田破产标志
今天
6
0
docker 使用mysql

1, 进入容器 比如 myslq1 里面进行操作 docker exec -it mysql1 /bin/bash 2. 退出 容器 交互: exit 3. mysql 启动在容器里面,并且 可以本地连接mysql docker run --name mysql1 --env MY...

之渊
今天
7
0
python数据结构

1、字符串及其方法(案例来自Python-100-Days) def main(): str1 = 'hello, world!' # 通过len函数计算字符串的长度 print(len(str1)) # 13 # 获得字符串首字母大写的...

huijue
今天
5
0
OSChina 周日乱弹 —— 我,小小编辑,食人族酋长

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @宇辰OSC :分享娃娃的单曲《飘洋过海来看你》: #今日歌曲推荐# 《飘洋过海来看你》- 娃娃 手机党少年们想听歌,请使劲儿戳(这里) @宇辰OSC...

小小编辑
今天
1K
11
MongoDB系列-- SpringBoot 中对 MongoDB 的 基本操作

SpringBoot 中对 MongoDB 的 基本操作 Database 库的创建 首先 在MongoDB 操作客户端 Robo 3T 中 创建数据库: 增加用户User: 创建 Collections 集合(类似mysql 中的 表): 后面我们大部分都...

TcWong
今天
40
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部