浅析Java内存模型--ClassLoader

在理解ClassLoader之前,我们先回顾下Java的一些相关知识。

基础

1. Java的主要特性

  • 平台无关性
  • 面向对象
  • GC(Java的垃圾回收机制)
  • 类库
  • 语言特性
  • 异常处理

2. 为什么JVM直接将 源码解析成机器码去执行

  • 准备工作:每次执行都需要各种检查
  • 兼容性:也可以将别的语言解析成字节码

Compile Once,Run Anywhere如何实现

在这里插入图片描述

​ java源码首先被编译成字节码,再由不同平台的JVM进行解析,Java语言在不同的平台上运行时不需要进行重新编译,Java虚拟机在执行字节码的时候,把字节码 转换成具体平台上的机器指令。

3. JVM如何加载.class文件

在这里插入图片描述

  • Class Loader:依据特定格式,加载class文件到内存
  • Execution Engine:对命令 进行 解析
  • Native Interface:融合不同开发语言的原生库为 Java所用
  • Runtime Data Area:JVM内存空间结构模型

4. 反射

​ Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意 一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java语言的反射机制。

5. 类从编译到执行的过程

  • 编译器将Xxx.java源文件编译为Xxx.class字节码文件
  • ClassLoader 将字节码转换为JVM中的Class<Xxx>对象
  • JVM利用Class<Xxx>对象实例化为Xxx对象

谈谈ClassLoader

​ ClassLoader 在 Java 中有着非常重要的作用,它主要工作在 Class 装载的加载阶段,其主要作用是从系统外部获得 Class 二进制数据流。它是 Java 的核心组件,所有的 Class 都是由 ClassLoader 进行加载的,ClassLoader 负责通过将 Class 文件里的二进制数据流装载进系统,然后交给 Java 虚拟机进行连接、初始化等操作。

1. ClassLoader的种类

  • BootStrapClassLoader:C++ 编写,加载核心库 java.*
  • ExcClassLoader:Java 编写,加载扩展库 javax.*
  • AppClassLoader:Java 编写,加载程序所在目录
  • 自定义 ClassLoader:Java 编写,定制化加载

2. 自定义 ClassLoader 的实现

关键函数

protected Class<?> findClass(String name) throws ClassNotFoundException {
    throw  new ClassNotFoundException(name);
}

protected final Class<?> defineClass(byte[] b, int off, int len) 
    throws ClassFormatError {
    
    return defineClass(null, b, off, len, null);
}

3. 类的加载方式

  • 隐式加载:new
  • 显示加载:loadClass,forName等

4. loadClass和forName的区别

类的装载过程

在这里插入图片描述

5. loadClass和forName的区别

  • Class.forName得到的class是已经初始化完成的
  • Classloader.loadClass得到的class是还没有链接的

6. 谈谈类加载器的双亲委派机制

不同类的加载方式和加载路径不同,为了实现分工,各自实现各自的功能,使得逻辑更加的明确,才有这么多共存的ClassLoader,加载类会根据各自的区域各司其职,而双亲委派机制会使这些加载器相互协调,形成一个整体。

双亲委派机制的原理图

在这里插入图片描述

loadClass源码解析

protected Class<?> loadClass(String name, boolean resolve) 
    throws ClassNotFoundException
{
	synchronized (getClassLoadingLock(name)) {
		// 首先,检测该类是否已被加载
		Class<?> c = findLoadedClass(name);
        if (c == null) {
        	long t0 = System.nanoTime();
            try {
            	// 检查上层是否已被加载
            	if (parent != null) {
            		c = parent.loadClass(name, false);
                } else {
                	c = findBootstrapClassOrNull(name);    
                }
            } catch (ClassNotFoundException e) {
				// 如果未发现类,则抛出异常
			}
			
            if (c == null) {
            	// 如果仍未找到,则委托findClass方法去寻找
            	long t1 = System.nanoTime();
            	// 自定义的findClass方法
            	c = findClass(name);
            	
            	sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
            	sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
            	sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
        	resolveClass(c);
        }
        return c;
	}
}

为什么要使用双亲委派机制去加载类?

为了避免多份同样字节码的加载。(通过逐层检查可以避免多份由各自加载的相同 class文件 )

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值