bootstraptable treeGrid 懒加载_Java类加载机制及自定义加载器

一:ClassLoader类加载器,主要的作用是将class文件加载到jvm虚拟机中。jvm启动的时候,并不是一次性加载所有的类,而是根据需要动态去加载类,主要分为隐式加载和显示加载。

  隐式加载:程序代码中不通过调用ClassLoader来加载需要的类,而是通过JVM类自动加载需要的类到内存中。例如,当我们在类中继承或者引用某个类的时候,JVM在解析当前这个类的时,发现引用的类不在内存中,那么就会自动将这些类加载到内存中。

  显示加载:代码中通过Class.forName(),this.getClass.getClassLoader.LoadClass(),自定义类加载器中的findClass()方法等。

二:jvm自带的加载器

(1)BootStrap ClassLoader:主要加载%JRE_HOME%lib下的rt.jar、resources.jar、charsets.jar和class等。可以通System.getProperty("sun.boot.class.path")

查看加载的路径,如下:

dfe3a415325efa6bbb107a3448a747cd.png


package test; public class TestGC { public static void main(String []args){ System.out.println(System.getProperty("sun.boot.class.path")); } }

dfe3a415325efa6bbb107a3448a747cd.png

显示结果如下:

D:Program FilesJavajdk1.7.0_45jrelibresources.jar;D:Program FilesJavajdk1.7.0_45jrelibrt.jar;D:Program FilesJavajdk1.7.0_45jrelibsunrsasign.jar;D:Program FilesJavajdk1.7.0_45jrelibjsse.jar;D:Program FilesJavajdk1.7.0_45jrelibjce.jar;D:Program FilesJavajdk1.7.0_45jrelibcharsets.jar;D:Program FilesJavajdk1.7.0_45jrelibjfr.jar;D:Program FilesJavajdk1.7.0_45jreclasses

(2)Extention ClassLoader:主要加载目录%JRE_HOME%libext目录下的jar包和class文件。也可以通过System.out.println(System.getProperty("java.ext.dirs"))查看加载类文件的路径。

(3)AppClassLoader:主要加载当前应用下的classpath路径下的类。之前我们在环境变量中配置的classpath就是指定AppClassLoader的类加载路径。

三:类加载器的继承关系

  先看一下这三个类加载器之间的继承关系,如下图:

a987fecec4e63ae71e0878220de229e2.png

ExtClassLoader,AppClassLoder继承URLClassLoader,而URLClassLoader继承ClassLoader,BoopStrap ClassLoder不在上图中,因为它是由C/C++编写的,它本身是虚拟机的一部分,并不是一个java类。jvm加载的顺序:BoopStrap ClassLoder-〉ExtClassLoader->AppClassLoder,下面看一段源码:

dfe3a415325efa6bbb107a3448a747cd.png


public class Launcher { private static Launcher launcher = new Launcher(); private static String bootClassPath = System.getProperty("sun.boot.class.path"); public static Launcher getLauncher() { return launcher; } private ClassLoader loader; public Launcher() { // Create the extension class loader ClassLoader extcl; try { extcl = ExtClassLoader.getExtClassLoader(); } catch (IOException e) { throw new InternalError( "Could not create extension class loader", e); } // Now create the class loader to use to launch the application try { loader = AppClassLoader.getAppClassLoader(extcl); } catch (IOException e) { throw new InternalError( "Could not create application class loader", e); } Thread.currentThread().setContextClassLoader(loader); } /* * Returns the class loader used to launch the main application. */ public ClassLoader getClassLoader() { return loader; } /* * The class loader used for loading installed extensions. */ static class ExtClassLoader extends URLClassLoader {} /** * The class loader used for loading from java.class.path. * runs in a restricted security context. */ static class AppClassLoader extends URLClassLoader {}

dfe3a415325efa6bbb107a3448a747cd.png

从源码中我们看到:(1)Launcher初始化的时候创建了ExtClassLoader以及AppClassLoader,并将ExtClassLoader实例传入到AppClassLoader中。

   (2)虽然上一段源码中没见到创建BoopStrap ClassLoader,但是程序一开始就执行了System.getProperty("sun.boot.class.path")。

四:类加载器之间的父子关系

    AppClassLoader的父加载器为ExtClassLoader,ExtClassLoader的父加载器为null,BoopStrap ClassLoader为顶级加载器。

下面一个小例子就可以证明,如下:新建一个Test类,可以通过getParent()方法获取上一层父机载器,执行如下代码:

dfe3a415325efa6bbb107a3448a747cd.png


package test; public class TestGC { public static void main(String []args){ System.out.println(Test.class.getClassLoader().toString()); System.out.println(Test.class.getClassLoader().getParent().toString()); System.out.println(Test.class.getClassLoader().getParent().getParent().toString()); } }

dfe3a415325efa6bbb107a3448a747cd.png

输出结果如下:

0840590ddc3aa7fa09eaf735f04943bb.png

五:类加载机制-双亲委托机制

  例如:当jvm要加载Test.class的时候,

  (1)首先会到自定义加载器中查找,看是否已经加载过,如果已经加载过,则返回字节码。

  (2)如果自定义加载器没有加载过,则询问上一层加载器(即AppClassLoader)是否已经加载过Test.class。

  (3)如果没有加载过,则询问上一层加载器(ExtClassLoader)是否已经加载过。

  (4)如果没有加载过,则继续询问上一层加载(BoopStrap ClassLoader)是否已经加载过。

  (5)如果BoopStrap ClassLoader依然没有加载过,则到自己指定类加载路径下("sun.boot.class.path")查看是否有Test.class字节码,有则返回,没有通

知下一层加载器ExtClassLoader到自己指定的类加载路径下(java.ext.dirs)查看。

  (6)依次类推,最后到自定义类加载器指定的路径还没有找到Test.class字节码,则抛出异常ClassNotFoundException。如下图:

2115a8a76cb8c8def0f588b846884f16.png

六:类加载过程的几个方法

  (1)loadClass (2)findLoadedClass (3)findClass

dfe3a415325efa6bbb107a3448a747cd.png


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) { //父加载器不为空,调用父加载器的loadClass c = parent.loadClass(name, false); } else { //父加载器为空则,调用Bootstrap Classloader c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); //父加载器没有找到,则调用findclass c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { //调用resolveClass() resolveClass(c); } return c; } }

dfe3a415325efa6bbb107a3448a747cd.png

七:自定义类加载器步骤

  (1)继承ClassLoader (2)重写findClass()方法 (3)调用defineClass()方法

  下面写一个自定义类加载器:指定类加载路径在D盘下的lib文件夹下。

  (1)新建一个Test.class类,代码如下:

dfe3a415325efa6bbb107a3448a747cd.png


package com.test; public class Test { public void say(){
System.out.println("Hello MyClassLoader"); } }

dfe3a415325efa6bbb107a3448a747cd.png

(2)cmd控制台执行javac Test.java,将生成的Test.class文件放到D盘lib文件夹->com文件夹->test文件夹下。

  (3)自定义类加载器,代码如下:

dfe3a415325efa6bbb107a3448a747cd.png


package test; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; public class MyClassLoader extends ClassLoader{ private String classpath; public MyClassLoader(String classpath) { this.classpath = classpath; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { try { byte [] classDate=getDate(name); if(classDate==null){} else{ //defineClass方法将字节码转化为类 return defineClass(name,classDate,0,classDate.length); } } catch (IOException e) { e.printStackTrace(); } return super.findClass(name); } //返回类的字节码 private byte[] getDate(String className) throws IOException{ InputStream in = null; ByteArrayOutputStream out = null; String path=classpath + File.separatorChar + className.replace('.',File.separatorChar)+".class"; try { in=new FileInputStream(path); out=new ByteArrayOutputStream(); byte[] buffer=new byte[2048]; int len=0; while((len=in.read(buffer))!=-1){ out.write(buffer,0,len); } return out.toByteArray(); } catch (FileNotFoundException e) { e.printStackTrace(); } finally{ in.close(); out.close(); } return null; } }

dfe3a415325efa6bbb107a3448a747cd.png

  测试代码如下:

dfe3a415325efa6bbb107a3448a747cd.png


package test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TestMyClassLoader { public static void main(String []args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{ //自定义类加载器的加载路径 MyClassLoader myClassLoader=new MyClassLoader("D:lib"); //包名+类名 Class c=myClassLoader.loadClass("com.test.Test"); if(c!=null){ Object obj=c.newInstance(); Method method=c.getMethod("say", null); method.invoke(obj, null); System.out.println(c.getClassLoader().toString()); } } }

dfe3a415325efa6bbb107a3448a747cd.png

输出结果如下:

b4b514da2ad8148f6c2a5f29fba60114.png

自定义类加载器的作用:jvm自带的三个加载器只能加载指定路径下的类字节码。如果某个情况下,我们需要加载应用程序之外的类文件呢?比如本地D盘下的,或者去加载网络上的某个类文件,这种情况就可以使用自定义加载器了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/437448.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Idea打可执行jar包

前些日子试了下idea打包&#xff0c;有些细节没太注意所以经常打包失败&#xff0c;要不然就是显示没有主清单属性&#xff0c;所以一直用eclipse打包&#xff0c;今天又重新捣鼓了一下&#xff0c;写下过程&#xff1a; 1. 先添加需要打jar包的主入口 第三步一定不要放在main…

安卓系统挂载NTFS格式硬盘_Mac 读写 NTFS硬盘管理开源工具NTFSTool

NTFSTool是Mac OS 下一款开源的 NTFS 磁盘格式读写工具&#xff0c;基于Electron和VUE编写。遵守MIT开源协议。支持 NTFS 磁盘读写、挂载&#xff0c;退出、管理等功能。系统检测到插入移动硬盘后&#xff0c;会自动弹出 NTFSTool 界面&#xff0c;并自动挂载硬盘。安装NTFSToo…

【转】刨根究底字符编码之九——字符编码方案的演变与字节序

字符编码方案的演变与字节序 一、字符编码方案的演变 1. 根据前面的介绍&#xff0c;对于字符编码方案的演变&#xff0c;我们大致上可简单地划分为三个阶段&#xff1a; ① ASCII编码方案阶段 → ② ANSI编码方案阶段 → ③ Unicode/UCS编码方案阶段。 在第一个阶段的ASCII…

python人工智能_人工智能人才缺口千万!学Python抓住风口机会

前不久教育界的一个消息&#xff0c;引发了广泛的关注。今年9月&#xff0c;浙江三到九年级信息技术课将替换新教材&#xff0c;八年级将新增Python课程内容。新高一信息技术编程语言由VB替换为Python&#xff0c;大数据、人工智能、程序设计与算法按照教材规划五六年级开始接触…

【转】刨根究底字符编码之十——Unicode字符集的字符编码方式

一、字符编码方式CEF的选择 1. 由于Unicode字符集非常大(并且作为开放字符集还在不断扩展之中)&#xff0c;有些字符的编号(即码点值)需要两个或两个以上字节来表示&#xff0c;而要对这样的编号进行编码&#xff0c;也必须使用两个或两个以上字节。 比如&#xff0c;汉字“…

【转】刨根究底字符编码之十一——UTF-8编码方式与字节序标记BOM

一、UTF-8编码方式 1. 接下来将分别介绍Unicode字符集的三种编码方式&#xff1a;UTF-8、UTF-16、UTF-32。这里先介绍应用最为广泛的UTF-8。 为满足基于ASCII、面向字节的字符处理的需要&#xff0c;Unicode标准中定义了UTF-8编码方式。UTF-8应该是目前应用最广泛的一种Unic…

流水灯verilog实验原理_IC设计实例解析之“流水线技术”

源自&#xff1a;微信公众号 “数字芯片实验室”在IC设计中&#xff0c;如果寄存器之间的组合逻辑延时过大&#xff0c;可能会称为设计中的关键路径&#xff0c;从而降低整个电路的工作频率。如下图所示&#xff0c;是一个输入和输出寄存的算术计算逻辑。在set_input_delay和se…

【转】刨根究底字符编码之十二——UTF-8究竟是怎么编码的

UTF-8究竟是怎么编码的 1. UTF-8编码是Unicode字符集的一种字符编码方式(CEF)&#xff0c;其特点是使用变长字节数(即变长码元序列或称变宽码元序列)来编码。目前一般是1到4个字节&#xff0c;当然&#xff0c;也可以更长。 为什么要变长呢&#xff1f;这可以理解为按需分配…

iphone闪退修复工具_升级 iOS 14.2 微信闪退?iPhone 12 维修贵

原标题&#xff1a;升级 iOS 14.2 微信闪退&#xff1f;iPhone 12 维修贵昨天&#xff0c;苹果推出 iOS 14.2 正式版系统&#xff0c;我相信你们都知道了&#xff0c;主要新增几点功能&#xff0c;并没有针对性解决耗电问题&#xff0c;而对 AirPods Pro 充电进行优化&#xff…

【转】刨根究底字符编码之十三——UTF-16编码方式

1. UTF-16编码方式源于UCS-2(Universal Character Set coded in 2 octets、2-byte Universal Character Set)。而UCS-2&#xff0c;是早期遗留下来的历史产物。 UCS-2将字符编号直接映射为字符编码(CEF&#xff0c;而非CES&#xff0c;详见前文中对现代字符编码模型的解释)&a…

java xml 默认名称空间 xpath_创意产业园办公空间设计

你说想要的样子永远不是现在你的样子&#xff0c;桃花源或许永远在每个人的心底。桃花源办公空间整体外观入口前厅及走廊空间天花板细节桃花源其实是我们每个人或者一群人的乌托邦&#xff0c;一座苏联式的厂房是心中桃花源的开端&#xff0c;光、空、间、穿、行、高、纵、新、…

【转】刨根究底字符编码之十四——UTF-16究竟是怎么编码的

1. 首先要注意的是&#xff0c;代理Surrogate是专属于UTF-16编码方式的一种机制&#xff0c;UTF-8和UTF-32是不用代理的。 如前文所述&#xff0c;为了让UTF-16能继续编码基本平面后面的增补平面中的码点值&#xff0c;于是扩展了UTF-16编码方式。 具体的扩展方法就是为其增…

java环境_配置java环境变量

1.找到此电脑我的电脑右键属性。2.点击高级系统设置。3.点击环境变量。4.点击新建。5.创建变量名JAVA_HOME必须是大写&#xff0c;变量值找到你的jdk的根目录复制下来&#xff0c;然后粘贴进去&#xff0c;点击确定。6.再次点击新建7.创建变量名为path、变量值&#xff0c;找到…

idea+JRebel实现项目热部署

今天发现这个插件&#xff0c;简直神了&#xff0c;太爽了&#xff0c;每次改完代码重启都要等半天&#xff0c;回不去了 第一步&#xff1a;安装插件 第二步&#xff1a;在线生成GUID 网址&#xff1a;在线GUID地址 第三步&#xff1a;打开jrebel 如下所示面板&#xff0c;选…

【转】刨根究底字符编码之十五——UTF-32编码方式

1. UTF-32在UTF目前常用的三种编码方式(UTF-8、UTF-16、UTF-32)中&#xff0c;是最为简单的一种编码方式。UTF-32编码方式不使用任何编码算法将Unicode字符码点值(即编号字符集CCS中的字符编号)转换为码元序列&#xff0c;而是将每个Unicode字符码点值直接表示为一个32位的码元…

小米手机证书信任设置在哪里_小米手机闹钟在哪里?闹钟怎么设置?怎么找到闹钟?...

随着智能手机的大量普及&#xff0c;人们会发现手机里的功能越来越多&#xff0c;绝不像以前那样只能打打电话发发短信那么简单了。而这些功能当中很多我们常用的功能有的人却不会用、不会设置&#xff0c;甚至根本找不到在哪里&#xff1f;比如说手机闹钟这个功能&#xff0c;…

【转】刨根究底字符编码之十六——Windows记事本的诡异怪事:微软为什么跟联通有仇?

1. 当用一个软件(比如Windows记事本或Notepad)打开一个文本文件时&#xff0c;它要做的第一件事是确定这个文本文件究竟是使用哪种编码方式保存的&#xff0c;以便于该软件对其正确解码&#xff0c;否则将显示为乱码。 一般软件确定文本文件编码方式的方法有如下三种&#xf…

win10切换输入法快捷键_输入法失灵怎么办?该怎么恢复?

我们都尝试过在使用win10的时候&#xff0c;输入法无法切换&#xff0c;只能打英文不能输入汉字&#xff0c;对于要打字、打游戏来说都是非常麻烦的。所以&#xff0c;当输入法有问题的时候&#xff0c;应该要怎么样修复&#xff1f;主编&#xff1a;渣渣辉&#xff0c;是兄弟就…

【转】刨根究底字符编码【2.0版】(1):开篇

首先跟大家分享一个有趣的亲身经历。有一次&#xff0c;在网上我看到有程序员发了一个帖子&#xff0c;帖子题目乍一看让人感到惊愕&#xff0c;但细一想又让我会心一笑。 这个帖子的题目大致上是这样的&#xff1a;字符编码是不是让程序员最感到恶心的问题&#xff1f; 更有…