日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

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

發布時間:2023/12/10 java 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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")

查看加載的路徑,如下:


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

顯示結果如下:

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的類加載路徑。

三:類加載器的繼承關系

  先看一下這三個類加載器之間的繼承關系,如下圖:

ExtClassLoader,AppClassLoder繼承URLClassLoader,而URLClassLoader繼承ClassLoader,BoopStrap ClassLoder不在上圖中,因為它是由C/C++編寫的,它本身是虛擬機的一部分,并不是一個java類。jvm加載的順序:BoopStrap ClassLoder-〉ExtClassLoader->AppClassLoder,下面看一段源碼:


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 {}

從源碼中我們看到:(1)Launcher初始化的時候創建了ExtClassLoader以及AppClassLoader,并將ExtClassLoader實例傳入到AppClassLoader中。

   (2)雖然上一段源碼中沒見到創建BoopStrap ClassLoader,但是程序一開始就執行了System.getProperty("sun.boot.class.path")。

四:類加載器之間的父子關系

    AppClassLoader的父加載器為ExtClassLoader,ExtClassLoader的父加載器為null,BoopStrap ClassLoader為頂級加載器。

下面一個小例子就可以證明,如下:新建一個Test類,可以通過getParent()方法獲取上一層父機載器,執行如下代碼:


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()); } }

輸出結果如下:

五:類加載機制-雙親委托機制

  例如:當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。如下圖:

六:類加載過程的幾個方法

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


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; } }

七:自定義類加載器步驟

  (1)繼承ClassLoader (2)重寫findClass()方法 (3)調用defineClass()方法

  下面寫一個自定義類加載器:指定類加載路徑在D盤下的lib文件夾下。

  (1)新建一個Test.class類,代碼如下:


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

(2)cmd控制臺執行javac Test.java,將生成的Test.class文件放到D盤lib文件夾->com文件夾->test文件夾下。

  (3)自定義類加載器,代碼如下:


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; } }

  測試代碼如下:


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()); } } }

輸出結果如下:

自定義類加載器的作用:jvm自帶的三個加載器只能加載指定路徑下的類字節碼。如果某個情況下,我們需要加載應用程序之外的類文件呢?比如本地D盤下的,或者去加載網絡上的某個類文件,這種情況就可以使用自定義加載器了。

總結

以上是生活随笔為你收集整理的bootstraptable treeGrid 懒加载_Java类加载机制及自定义加载器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。