JVM学习————类加载子系统(二)

类加载子系统

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CJMZ4iAl-1617500020963)(JVM.assets/image-20210329135806176.png)]

  • 类加载器负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识
  • ClassLoader只负责class文件的加载,至于是否可以运行,则由Execution Engine决定
  • 加载类信息存放于一块称为方法区的内存空间。除了类信息外,方法区还会存放运行时常量池的信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)

类加载器ClassLoader角色

  1. Class File存在本地硬盘上,经过类加载器后,最终要实例化出n个一模一样的实例
  2. Class File加载到JVM中,被称为DNA元数据模板,放在方法区
  3. .Class文件—>JVM—>最终成为元数据模板,此过程就要一个类加载器

类加载过程

加载(Loading)—>链接(Linking)【验证、准备、解析】—>初始化(Initialization)

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

    • 主要验证当前加载的字节码文件符合JVM的规范,不会对虚拟机产生损害
    • 主要包括四种验证:文件格式验证,元数据验证,字节码验证,符号引用验证
  • 准备

    • 类变量分配内存并设置默认初始值,即零【private static int a = 1; prepare:a=0—>initial:a=1】
    • 不包含final修饰【常量,是在常量池中】的static变量,因为final在编译时就会分配,准备阶段会显示初始化
    • 不会为Java实例变量分配初始化,类变量会分配到方法区中,而实例变量会随着对象一起分配到Java堆中
  • 解析

    • 常量池的符合引用转为直接引用
    • 事实上,解析操作会伴随着JVM初始化之后操作
    • 符合引用就是一组符合来描述所引用的目标
    • 解析主要针对类或者接口、字段、接口方法、方法类型等
初始化
  • 初始化阶段就是执行构造器方法()的过程

  • 此方法不用定义,是由javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来的

  • 构造器方法中指令按语句在源文件中出现的顺序执行

  • ()不同于类的构造器

  • 若该类具有父类,会先执行父类的()

  • JVM必须保证一个类的()在多线程下同步加锁

  • public class Static {
        private static int a = 5;
    
        static {
            a = 10;
            b = 50;
            System.out.println(a);
    //        System.out.println(b);//报错,非法前向引用
        }
    
        private static int b = 20;
    
        public static void main(String[] args) {
            System.out.println(a);//10
            System.out.println(b);//20  静态变量  prepare分配内存并赋默认值b=0   initial赋值50-->20
        }
    }
    
  • 任何一个类声明以后,都会有一个类构造器()

- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0lsm95JJ-1617500020964)(JVM.assets/image-20210330172224156.png)]

  • 当声明静态变量时会出现()

- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JgGyx0dm-1617500020965)(JVM.assets/image-20210330172404838.png)]

类加载器的分类

  • JVM支持两种类型的类加载器,分别是引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader)
  • JVM对自定义类加载器的定义,将所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器
public class ClassLoaderTest {
    public static void main(String[] args) {
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);//系统类加载器   sun.misc.Launcher$AppClassLoader@18b4aac2

        ClassLoader extClassLoader = systemClassLoader.getParent();
        System.out.println(extClassLoader);//扩展类加载器   sun.misc.Launcher$ExtClassLoader@1540e19d

        ClassLoader bootstrapClassLoader = extClassLoader.getParent();
        System.out.println(bootstrapClassLoader);//引导类加载器   null

        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader);//系统类加载器   sun.misc.Launcher$AppClassLoader@18b4aac2

        ClassLoader stringLoader = String.class.getClassLoader();
        System.out.println(stringLoader);//引导类加载器   null

    }
}
虚拟机自带的加载器
启动类加载器(引导类加载器 Bootstrap ClassLoader)
  • 此类加载器一般使用c/c++实现,嵌套在JVM内部
  • 用来加载JVM的核心类库(rt.jar,resources.jar…),用于提供JVM自身需要的类
  • 不继承java.lang.ClassLoader,没有父加载器
  • 加载扩展类和应用程序类加载器,并指定为它们的父加载器
  • 处于安全考虑,Bootstrap启动类加载器包名为java、javax、sum等开头的类

sun.misc.Launcher是Java虚拟机的一个入口应用

扩展类加载器
  • Java语言编写,由sun.misc.Launcher$ExtClassLoader实现
  • 派生与ClassLoader类
  • 父加载器为启动类加载器
  • 从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录jre/lib/ext子目录(扩展目录)下面加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载
应用程序类加载器
  • Java语言编写,由sun.misc.Launcher$AppClassLoader实现
  • 派生与ClassLoader类
  • 父加载器为启动类加载器
  • 它负责环境变量classpath或系统属性java.class.path指定路径下的类库
  • 该类加载是程序中默认的加载器,一般来说,Java应用的类都是由他来加载的
  • 通过ClassLoader#getSystemClassLoader()可以获取到该类加载器
public class ContainClassLoader {
    public static void main(String[] args) {
        //引导类加载器中加载的api的url
        URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
        for (URL urL : urLs) {
            System.out.println(urL);
        }
        //jce.jar中的.class文件,其类加载器是Bootstrap
        ClassLoader classLoader = TlsMasterSecret.class.getClassLoader();
        System.out.println(classLoader);//null


        //扩展类加载器中加载的api的url
        String property = System.getProperty("java.ext.dirs");
        for (String s : property.split(";")) {
            System.out.println(s);
        }
        ClassLoader classLoader1 = EventID.class.getClassLoader();
        System.out.println(classLoader1);//sun.misc.Launcher$ExtClassLoader@1540e19d
    }
}
用户自定义类加载器

在Java日常开发中,类的加载器几乎是由上述3种类加载器相互配合完成的。在必要时,我们还可以自定义类加载器,来定制类的加载方式

为什么要自定义类的加载器?

  • 隔离加载类
  • 修改类加载方式
  • 扩展加载源
  • 放在源码泄露

用户自定义加载器的实现步骤:

  1. 继承抽象类CalssLoader
  2. JDK1.2之前重写loadClass(),JDK1.2之后将自己的加载逻辑写在findClass()
  3. 如果没有太过于复杂的需求可以直接继承URLClassLoader类,这样可以避免自己去编写findClass()以及获取字节码流的方式,是自定义类加载器更加简介

获取加载器的方法

  • clazz.getClassLoader()
  • Thread.currentThread().getContextClassLoader()
  • ClassLoader.getSystemClassLoader()
  • DriverManager.getCallerClassLoader()
public class GetClassLoader {
    public static void main(String[] args) {
        //1.
        try {
            Class<?> aClass = Class.forName("java.lang.String");
            ClassLoader classLoader = aClass.getClassLoader();//null
            System.out.println(classLoader);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //2.
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        System.out.println(classLoader);//sys
        //3.
        ClassLoader classLoader1 = ClassLoader.getSystemClassLoader().getParent();
        System.out.println(classLoader1);//ext
    }
}

双亲委派机制

Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将他的class文件加载到内存生成class对象,而且加载某个类的class文件时,Java虚拟机采用的是双亲委派机制,即把请求交由父类处理,它是一种任务委派模式

优势

  1. 避免类的重复加载
  2. 保护程序安全,防止核心API被随意篡改

工作原理

  1. 如果一个类加载器收到加载一个类的请求,他不会自己先去加载,会先交给父加载器去加载
  2. 如果父加载器还有父加载器,那么会继续向上委托,直到到引导类加载器
  3. 如果父加载器可以完成类加载任务,那么就由父加载器完成,如果不能,子类加载器才会去尝试完成,这就是双亲委派机制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ZVqUgeK-1617500020966)(JVM.assets/image-20210401173224214.png)]

报错原因:首先会一直向上请求到引导类加载器,去加载此类,此时引导类加载器可以加载String类,完成请求,但是引导类加载器的String没有main(),因此会报错

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zd8eyFxz-1617500020967)(JVM.assets/image-20210401172148323.png)]

报错原因:访问java.lang 包是要权限的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xBppUB6G-1617500020968)(JVM.assets/image-20210401175221903.png)]

沙箱安全机制

对于自定义的java.lang.String.class 在加载的过程中还是会先去加载rt.jar包中的String但是此jar包没有main(),这样就可以保证对java核心源码的保护,这就是沙箱安全机制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园的建设目标是通过数据整合、全面共享,实现校园内教学、科研、管理、服务流程的数字化、信息化、智能化和多媒体化,以提高资源利用率和管理效率,确保校园安全。 智慧校园的建设思路包括构建统一支撑平台、建立完善管理体系、大数据辅助决策和建设校园智慧环境。通过云架构的数据中心与智慧的学习、办公环境,实现日常教学活动、资源建设情况、学业水平情况的全面统计和分析,为决策提供辅助。此外,智慧校园还涵盖了多媒体教学、智慧录播、电子图书馆、VR教室等多种教学模式,以及校园网络、智慧班牌、校园广播等教务管理功能,旨在提升教学品质和管理水平。 智慧校园的详细方案设计进一步细化了教学、教务、安防和运维等多个方面的应用。例如,在智慧教学领域,通过多媒体教学、智慧录播、电子图书馆等技术,实现教学资源的共享和教学模式的创新。在智慧教务方面,校园网络、考场监控、智慧班牌等系统为校园管理提供了便捷和高效。智慧安防系统包括视频监控、一键报警、阳光厨房等,确保校园安全。智慧运维则通过综合管理平台、设备管理、能效管理和资产管理,实现校园设施的智能化管理。 智慧校园的优势和价值体现在个性化互动的智慧教学、协同高效的校园管理、无处不在的校园学习、全面感知的校园环境和轻松便捷的校园生活等方面。通过智慧校园的建设,可以促进教育资源的均衡化,提高教育质量和管理效率,同时保障校园安全和提升师生的学习体验。 总之,智慧校园解决方案通过整合现代信息技术,如云计算、大数据、物联网和人工智能,为教育行业带来了革命性的变革。它不仅提高了教育的质量和效率,还为师生创造了一个更加安全、便捷和富有智慧的学习与生活环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值