java学习记录-类加载机制

ayasatomayoi      2022-04-19     327

关键词:

类加载机制主要分3块:类加载器(ClassLoader)、类加载过程和双亲委托(破坏双亲委托)

 

类加载器:是Java运行时环境(Java Runtime Environment)的一部分,负责动态加载Java类到Java虚拟机的内存空间中。jdk自带了三种类加载器,分别是引导类加载器(Bootstrap ClassLoader),扩展类加载器(Extension ClassLoader),应用程序类加载器(Application ClassLoader)。后两种加载器是继承自抽象类java.lang.ClassLoader

 

类加载过程:类加载过程包括加载、验证、准备、解析和初始化五个阶段。

1、加载
简单的说,类加载阶段就是由类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部,并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的java.lang.Class对象实例(Java虚拟机规范并没有明确要求一定要存储在堆区中,只是hotspot选择将Class对戏那个存储在方法区中),这个Class对象在日后就会作为方法区中该类的各种数据的访问入口。
2、链接
链接阶段要做的是将加载到JVM中的二进制字节流的类数据信息合并到JVM的运行时状态中,经由验证、准备和解析三个阶段。
1)、验证
验证类数据信息是否符合JVM规范,是否是一个有效的字节码文件,验证内容涵盖了类数据信息的格式验证、语义分析、操作验证等。
格式验证:验证是否符合class文件规范
语义验证:检查一个被标记为final的类型是否包含子类;检查一个类中的final方法视频被子类进行重写;确保父类和子类之间没有不兼容的一些方法声明(比如方法签名相同,但方法的返回值不同)
操作验证:在操作数栈中的数据必须进行正确的操作,对常量池中的各种符号引用执行验证(通常在解析阶段执行,检查是否通过富豪引用中描述的全限定名定位到指定类型上,以及类成员信息的访问修饰符是否允许访问等)

2)、准备
为类中的所有静态变量分配内存空间,并为其设置一个初始值(由于还没有产生对象,实例变量不在此操作范围内)
被final修饰的静态变量,会直接赋予原值;类字段的字段属性表中存在ConstantValue属性,则在准备阶段,其值就是ConstantValue的值
3)、解析
将常量池中的符号引用转为直接引用(得到类或者字段、方法在内存中的指针或者偏移量,以便直接调用该方法),这个可以在初始化之后再执行。
可以认为是一些静态绑定的会被解析,动态绑定则只会在运行是进行解析;静态绑定包括一些final方法(不可以重写),static方法(只会属于当前类),构造器(不会被重写)
3、初始化
将一个类中所有被static关键字标识的代码统一执行一遍,如果执行的是静态变量,那么就会使用用户指定的值覆盖之前在准备阶段设置的初始值;如果执行的是static代码块,那么在初始化阶段,JVM就会执行static代码块中定义的所有操作。
所有类变量初始化语句和静态代码块都会在编译时被前端编译器放在收集器里头,存放到一个特殊的方法中,这个方法就是<clinit>方法,即类/接口初始化方法。该方法的作用就是初始化一个中的变量,使用用户指定的值覆盖之前在准备阶段里设定的初始值。任何invoke之类的字节码都无法调用<clinit>方法,因为该方法只能在类加载的过程中由JVM调用。
如果父类还没有被初始化,那么优先对父类初始化,但在<clinit>方法内部不会显示调用父类的<clinit>方法,由JVM负责保证一个类的<clinit>方法执行之前,它的父类<clinit>方法已经被执行。
JVM必须确保一个类在初始化的过程中,如果是多线程需要同时初始化它,仅仅只能允许其中一个线程对其执行初始化操作,其余线程必须等待,只有在活动线程执行完对类的初始化操作之后,才会通知正在等待的其他线程。

技术分享图片

 

双亲委托(破坏双亲委托):

程序运行后,编译器把Java文件编译成class文件后,首先负责加载的是系统类加载器,但它不会马上加载,而是将此任务移送给它的父类加载器扩展类加载器加载,扩展类加载器也是将此任务移送给引导类加载器加载。

class文件到了引导类加载器那,它先判断能不能加载这个类,如果能,就加载;不能,移送给其子加载器,以此类推。最终我们编写的class都会配置在classpath环境中,所以,这个类加载任务还是由系统类加载器完成。如果系统类加载器都不能加载,就抛出ClassNotFoundException。

当一个class加载到JVM中,类加载阶段已经完成。接下来JVM分配内存,对整个class文件(文件里面都是二进制的汇编命令)进行内容解析(JVM对二进制的命令逐行解析,交由CPU执行)。

双亲委托机制:这种机制的好处就是不会随随便便的加载用户写的类。

技术分享图片

 

 双亲委托在jdk8中的实现,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);
                    // 前面提到,bootstrap classloader的类加载器为null,通过find方法来获得
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                }

                if (c == null) {
                    // 如果还是没有获得该类,调用findClass找到类
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // jvm统计
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            // 连接类
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

如果自定义类加载器要破坏双亲委托,重写loadClass方法即可,反之,重写findClass方法。这样保证了不会随随便便的加载用户写的类

---------------------------------------------------------------------------------------------------------------

附:是否可以写一个类叫"java.lang.String"

不能写这个类,我们自定义的类加载器必须继承自ClassLoader,其loadClass()方法里调用了父类的defineClass()方法,并最终调到preDefineClass()方法,因此我们自定义的类加载器也是不能加载以“java.”开头的java类的。



 

参考资料:

https://www.cnblogs.com/joemsu/p/9310226.html

https://blog.csdn.net/tang9140/article/details/42738433

https://www.cnblogs.com/xiaoxian1369/p/5498817.html





















java类加载机制(仅作记录)

下面声明类看看测试结果: [java] viewplain copy package com.shareniu;      public class HelloA {      { &nbs 查看详情

深度学习java的类加载机制(代码片段)

java的类加载机制前言学生时代应抱着问题去学习一门语言,例如:在学习java语言的过程中,我遇到过java主方法main里面参数到底是存的什么?还有java语言的Object是如何成为所有类的父类的?java虚拟机到底如... 查看详情

java并发编程艺术学习第二章java并发机制的底层实现原理学习记录volatile

章节介绍  这一章节主要学习java并发机制的底层实现原理。主要学习volatile、synchronized和原子操作的实现原理。Java中的大部分容器和框架都依赖于此。  Java代码==经过编译==》Java字节码==通过类加载器==》JVM(jvm执行字节码... 查看详情

重点知识学习(4.1)--[jvm概述,类加载机制]

文章目录一:JVM(Java虚拟机)概述二:JVM类加载[classLoader]类加载子系统加载过程之-->加载阶段加载过程之-->链接阶段加载过程之-->初始化阶段类加载器(1)引导类加载器(启动类加载器BootStrapClassLoader)(2)扩展类加载器(ExtensionClassLo... 查看详情

一夜搞懂|jvm类加载机制

...我的Github个人博客,欢迎大佬们光临寒舍:我的GIthub博客学习导图一.为什么要学习类加载机制?今天想跟大家唠嗑唠嗑Java的类加载机制,这是Java的一个很重要的创新点,曾经也是Java流行的重要原因之一。Oracle当初引入这个机... 查看详情

jvm学习记录-类加载器(代码片段)

前言JVM设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作房东Java虚拟机外面去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块称为“类加... 查看详情

java初识类加载机制第13节

...sp;  从这章开始,我们就进入虚拟机类加载机制的学习了。那么什么是类加载呢?当我们写完一个Java类的时候,并不是直接就可以运行的,它还要编译成.class文件,再由虚拟机解释给当前的操作系统去执行。这些过程都... 查看详情

jvm学习笔记——虚拟机类加载机制

概述虚拟机把描述符的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。类的生命周期类从被加载到虚拟机内存中开始࿰... 查看详情

12000+字java反射,一起全面了解java反射机制,为学习框架铺路(代码片段)

文章目录Java反射机制理解Class类获取Class类实例类的加载过程类加载器ClassLoader创建运行时类的对象获取运行时类的结构调用运行时类的指定结构动态代理Java反射机制Reflection是被视为动态语言的关键,反射机制允许程序在执... 查看详情

深入理解jvm学习笔记——-7虚拟机类加载机制★

你只管努力,——剩下的交给时光。在Java语言中,类型的加载、连接和初始化都是在程序运行期间完成的。我们写的java文件是不能直接运行的,可以在IDE中右键文件名点击运行,这中间其实掺杂了一系列的复杂... 查看详情

jvm学习笔记一:类加载子系统(代码片段)

目录 前言类加载子系统的作用类加载器角色的位置类加载器分类虚拟机自带的加载器启动类加载器(引导类加载器)扩展类加载器系统类加载器用户自定义类加载器什么时候需要自定义类加载器?如何自定义类加载... 查看详情

深入理解java:类加载机制及反射

  说明:本文乃学习整理参考而来.一、Java类加载机制1.概述       Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造... 查看详情

java反射机制学习:初始反射机制

  本人小白一枚,想和大家一起分享我学习java的笔记和心得。 反射机制: 指的是可以于运行时加载、探知、使用编译期间完全未知的类。 程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的类,... 查看详情

深入理解jvm学习笔记——-7虚拟机类加载机制★

你只管努力,——剩下的交给时光。在Java语言中,类型的加载、连接和初始化都是在程序运行期间完成的。我们写的java文件是不能直接运行的,可以在IDE中右键文件名点击运行,这中间其实掺杂了一系列的复杂... 查看详情

java类加载过程以及双亲委派机制

...怕在这样的状态下写出来的东西出错。为了不让自己荒废学习的劲头和习惯,今天周日,也打算写一篇博客,就算是为了给自己以前立的flag(每个月必须写几篇博客)的实现。那么本次博客的主题我选择了java的类加载过程的探究... 查看详情

jmv的学习

一.JVM学习1.1JVM运行机制的最重要的三点:加载(类加载器,classloader)、内存管理(包含GC)、执行。如果再加上JDK所作的把java文件编译为二进制class文件的步骤,就组成了Java代码的执行机制三部曲:编译–>加载–>执行2.1J... 查看详情

java类加载机制

1.类加载器  类加载器(ClassLoader),顾名思义,即加载类的东西,在我们使用一个类之前,JVM需要先将该类的字节码文件(.class)文件从磁盘/网盘或其他的来源加载到内存中,并对字节码进行解析生成对应的Class对象,这就是类加载器的功... 查看详情

jvm学习.03类加载机制

1、前言从事Java开发工作的都知道,Java程序提交到JVM运行时,需要编译成Class文件,才能被JVM加载运行。那么这些Class文件进入到虚拟机后会发生什么?以及Class是如何被加载的?这些都是本文要讲解的部分。2... 查看详情