JVM(5)——類加載機制

      網友投稿 882 2025-03-31

      文章目錄

      1、類加載機制

      1.1、類加載運行全過程

      1.2、類的加載時機

      1.3、不會初始化(可能會加載)

      1.4、類加載器和雙親委派機制

      1.4.1、類加載器特點

      1.4.2、類加載器初始化過程

      1.4.3、全盤加載機制

      1.4.4、自定義類加載器

      1.4.5、打破雙親加載機制

      1.4.6、擴展:tomcat如何打破雙親加載機制

      1.5、顯示當前ClassLoader加載了哪些Jar

      1.6、添加引用類的幾種方式

      1、類加載機制

      1.1、類加載運行全過程

      當我們啟動一個Java文件的時候,比如

      點擊main方法時,首先需要通過類加載器把主類加載到JVM,具體如下

      粗略地:

      地址:https://www.processon.com/view/link/613df3f6e401fd7aedfe372d

      詳細地:

      細分:

      加載

      在硬盤上查找并通過IO讀入字節碼文件,使用到類時才會加載,例如調用類的 main()方法,new對象等等,在加載階段會在內存中生成一個代表這個類的 java.lang.Class對象,作為方法區這個類的各種數據的訪問入口 (找 Class 文件)

      驗證

      校驗字節碼文件的正確性(驗證格式、依賴)

      準備

      給類的靜態變量分配內存,并賦予默認值(靜態字段、方法表)

      解析

      將符號引用替換為直接引用,該階段會把一些靜態方法(符號引用,比如 main()方法)替換為指向數據存內存的指針或句柄等(直接引用),這是所謂的靜態鏈接過 程(類加載期間完成),動態鏈接(調方法)是在程序運行間完成的將符號引用替換為直接引用(符號解析為引用)

      初始化

      對類的靜態變量初始化為指定的值,執行靜態代碼塊(構造器、靜態變量賦值、靜態代碼塊)

      使用

      卸載

      鏈接:https://www.processon.com/view/link/613e05d8e401fd7aedfe52f3

      類被加載到方法區中后后主要包含 運行時常量池、類型信息、字段信息、方法信息、類加載器的引用、對應class實例的引用等信息。

      **類加載器的引用:**這個類到類加載器實例的引用

      **對應class實例的引用:**類加載器在加載類信息放到方法區中后,會創建一個對應的Class 類型的對象實例放到堆(Heap)中, 作為開發人員訪問方法區中類定義的入口和切入點

      **注意:**主類在運行過程中如果使用到其它類,會逐步加載這些類。 jar包或war包里的類不是一次性全部加載的,是使用到時才加載。

      package com.zhz; /** * @author zhouhengzhe * @Description: 測試動態加載 * @date 2021/9/12下午9:55 * @since */ public class TestDynamicLoad { static { System.out.println("*************load TestDynamicLoad************"); } public static void main(String[] args) { new A(); System.out.println("*************load test************"); B b = null; //B不會加載,除非這里執行new B() } } class A { static { System.out.println("*************load A************"); } public A() { System.out.println("*************initial A************"); } } class B { static { System.out.println("*************load B************"); } public B() { System.out.println("*************initial B************"); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      ![image.png](https://img-blog.csdnimg.cn/img_convert/56f3b752014b3b7ada2ef571f541cf11.png#clientId=u3b241770-215f-4&from=paste&height=153&id=kCICl&margin=[object Object]&name=image.png&originHeight=306&originWidth=1262&originalType=binary&ratio=1&size=74590&status=done&style=none&taskId=u93065b49-3993-4fd5-8715-f208e061184&width=631)

      1.2、類的加載時機

      虛擬機啟動時,初始化用戶指定的主類,就是啟動執行的 main 方法所在的類;

      當遇到用以新建目標類實例的 new 指令時,初始化 new 指令的目標類,就是 new 一個類的時候要初始化;

      當遇到調用靜態方法的指令時,初始化該靜態方法所在的類;

      當遇到訪問靜態字段的指令時,初始化該靜態字段所在的類;

      子類的初始化會觸發父類的初始化;

      如果一個接口定義了 default 方法,那么直接實現或者間接實現該接口的類的初始化,會觸發該接口的初始化;

      使用反射 API 對某個類進行反射調用時,初始化這個類,其實跟前面一樣,反射調用要么是已經有實例了,要么是靜態方法,都需要初始化;

      當初次調用 MethodHandle 實例時,初始化該 MethodHandle 指向的方法所在的類。

      1.3、不會初始化(可能會加載)

      通過子類引用父類的靜態字段,只會觸發父類的初始化,而不會觸發子類的初始化。

      定義對象數組,不會觸發該類的初始化。

      常量在編譯期間會存入調用類的常量池中,本質上并沒有直接引用定義常量的類,不會觸發定義常量所在的類。

      通過類名獲取 Class 對象,不會觸發類的初始化,Hello.class 不會讓 Hello 類初始化。

      通過 Class.forName 加載指定類時,如果指定參數 initialize 為 false 時,也不會觸發類初始化,其實這個參數是告訴虛擬機,是否要對類進行初始化。(Class.forName(“jvm.Hello”))默認會加載 Hello 類。

      通過 ClassLoader 默認的 loadClass 方法,也不會觸發初始化動作(加載了,但是不初始化)。

      1.4、類加載器和雙親委派機制

      引導類加載器(BootstrapClassLoader):負責加載支撐JVM運行的位于JRE的lib目錄下的核心類庫,比如rt.jar、charsets.jar等

      擴展類加載器(ExtClassLoader):負責加載支撐JVM運行的位于JRE的lib目錄下的ext擴展目錄中的JAR類包

      應用程序類加載器(AppClassLoader):負責加載ClassPath路徑下的類包,主要就是加載你自己寫的那些類

      自定義加載器:負責加載用戶自定義路徑下的類包

      雙親委派機制是什么?

      1、我們寫的類會由AppClassLoader先去加載,然后AppClassLoader會委托ExtClassLoader去加載,ExtClassLoader會委托BootstrapClassLoader去加載

      2、如果BootstrapClassLoader加載找不到目標類,就會回退給ExtClassLoader,讓ExtClassLoader去加載,ExtClassLoader加載找不到目標類,就由AppClassLoader自己加載。

      源碼(證據):

      //ClassLoader的loadClass方法,里面實現了雙親委派機制 protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded // 檢查當前類加載器是否已經加載了該類 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) { // 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(); //都會調用URLClassLoader的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(c);//不會執行 } return c; } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      解釋:

      1、檢查指定名稱的類是否已經加載過,如果已經加載過,就直接返回。

      2、如果沒加載過,就判斷一下是否有父加載器,如果有父加載器,由父加載器加載(即調用parent.loadClass(name, false)),如果沒有父加載器就調用BootstrapClassLoader->findBootstrapClassOrNull(name);來加載。

      3、如果父加載器及BootstrapClassLoader都沒有找到指定的類,那么調用當前類加載器的 findClass方法來完成類加載。

      1.4.1、類加載器特點

      1、雙親委托

      2、防止重復加載:當父類加載器加載過后,子類加載器就不需要再次加載了,保證被加載類的唯一性

      3、負責依賴

      4、緩存加載

      5、沙箱安全機制:防止Java核心類被隨意篡改

      package java.lang; /** * @author zhouhengzhe * @Description: 沙箱安全機制 * @date 2021/9/18上午2:34 * @since */ public class String { public static void main(String[] args) { System.out.println("aaa"); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      1.4.2、類加載器初始化過程

      //Launcher的構造方法 public Launcher() { Launcher.ExtClassLoader var1; try { //構造擴展類加載器,在構造的過程中將其父加載器設置為null var1 = Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError("Could not create extension class loader", var10); } try { //構造應用類加載器,在構造的過程中將其父加載器設置為ExtClassLoader, //Launcher的loader屬性值是AppClassLoader,我們一般都是用這個類加載器來加載我們自己寫的應用程序 this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader", var9); } Thread.currentThread().setContextClassLoader(this.loader); String var2 = System.getProperty("java.security.manager"); if (var2 != null) { SecurityManager var3 = null; if (!"".equals(var2) && !"default".equals(var2)) { try { var3 = (SecurityManager)this.loader.loadClass(var2).newInstance(); } catch (IllegalAccessException var5) { } catch (InstantiationException var6) { } catch (ClassNotFoundException var7) { } catch (ClassCastException var8) { } } else { var3 = new SecurityManager(); } if (var3 == null) { throw new InternalError("Could not create SecurityManager: " + var2); } System.setSecurityManager(var3); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      1.4.3、全盤加載機制

      顯示指定某一個類加載器加載類

      1.4.4、自定義類加載器

      package com.zhz.bytecode; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author zhouhengzhe * @Description: 自定義類加載器 * @date 2021/9/22上午11:29 * @since */ public class CustomClassLoaderTest { static class CustomClassLoader extends ClassLoader { private String classpath; public CustomClassLoader(String classpath) { this.classpath = classpath; } @Override protected Class findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name); //defineClass將一個字節數組轉為Class對象,這個字節數組是class文件讀取后最終的字節數組。 return defineClass(name,data,0,data.length); } catch (IOException e) { e.printStackTrace(); throw new ClassNotFoundException(); } } private byte[] loadByte(String name) throws IOException { // name = name.replaceAll("\.", "/"); FileInputStream fis = new FileInputStream(classpath + "/" + name + ".class"); int len = fis.available(); byte[] data = new byte[len]; fis.read(data); fis.close(); return data; } } public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //初始化自定義類加載器,會先初始化父類ClassLoader,其中會把自定義類加載器的父加載 器設置為應用程序類加載器AppClassLoader CustomClassLoader customClassLoader=new CustomClassLoader("/Users/mac/Documents/ideaproject/Java/Java基礎/jvm-learn-demo/src/main/java/"); //D盤創建 test/com/zhz/bytecode 幾級目錄,將User類的復制類User1.class丟入該目錄 Class clazz = customClassLoader.loadClass("com.zhz.bytecode.Hello"); Object instance = clazz.newInstance(); Method method = clazz.getDeclaredMethod("hello", null); method.invoke(instance,null); System.out.println(clazz.getClassLoader().getClass().getName()); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      1.4.5、打破雙親加載機制

      再來一個沙箱安全機制示例,嘗試打破雙親委派機制,用自定義類加載器加載我們自己實現的 java.lang.String.class(失敗,Java不給改核心類)

      示例:

      package com.zhz.bytecode; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author zhouhengzhe * @Description: 打破雙親加載機制 * @date 2021/9/22下午12:48 * @since */ public class BreakParentLoadingMechanism { static class CustomClassLoader extends ClassLoader { private String classpath; public CustomClassLoader(String classpath) { this.classpath = classpath; } /** * 重寫類加載方法,實現自己的加載邏輯,不委派給雙親加載 * @param name * @return: Class * @author: zhouhengzhe * @date: 2021/9/22 */ @Override public Class loadClass(String name,boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } if (resolve) { resolveClass(c); } return c; } } @Override protected Class findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name); //defineClass將一個字節數組轉為Class對象,這個字節數組是class文件讀取后最終的字節數組。 return defineClass(name,data,0,data.length); } catch (IOException e) { e.printStackTrace(); throw new ClassNotFoundException(); } } private byte[] loadByte(String name) throws IOException { // name = name.replaceAll("\.", "/"); FileInputStream fis = new FileInputStream(classpath + "/" + name + ".class"); int len = fis.available(); byte[] data = new byte[len]; fis.read(data); fis.close(); return data; } } public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //初始化自定義類加載器,會先初始化父類ClassLoader,其中會把自定義類加載器的父加載 器設置為應用程序類加載器AppClassLoader CustomClassLoaderTest.CustomClassLoader customClassLoader=new CustomClassLoaderTest.CustomClassLoader("/Users/mac/Documents/ideaproject/Java/Java基礎/jvm-learn-demo/src/main/java/"); //D盤創建 test/com/zhz/bytecode 幾級目錄,將User類的復制類User1.class丟入該目錄 Class clazz = customClassLoader.loadClass("java.lang.String"); Object instance = clazz.newInstance(); Method method = clazz.getDeclaredMethod("sout", null); method.invoke(instance,null); System.out.println(clazz.getClassLoader().getClass().getName()); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      77

      78

      79

      80

      81

      82

      83

      84

      85

      86

      87

      ![image.png](https://img-blog.csdnimg.cn/img_convert/6d660ef9dd0bb8c7edd87c0f78f401dd.png#clientId=ue853169d-3846-4&from=paste&height=118&id=u75c6f481&margin=[object Object]&name=image.png&originHeight=235&originWidth=900&originalType=binary&ratio=1&size=118165&status=done&style=none&taskId=u48d3a5f3-80fb-4329-9210-fa13d2124aa&width=450)

      1.4.6、擴展:tomcat如何打破雙親加載機制

      Tomcat類加載機制詳解

      解釋:

      CommonClassLoader能加載的類都可以被CatalinaClassLoader和SharedClassLoader使用, 從而實現了公有類庫的共用,而CatalinaClassLoader和SharedClassLoader自己能加載的類則 與對方相互隔離。

      WebAppClassLoader可以使用SharedClassLoader加載到的類,但各個WebAppClassLoader 實例之間相互隔離。

      而JasperLoader的加載范圍僅僅是這個JSP文件所編譯出來的那一個.Class文件,它出現的目的 就是為了被丟棄:當Web容器檢測到JSP文件被修改時,會替換掉目前的JasperLoader的實例, 并通過再建立一個新的Jsp類加載器來實現JSP文件的熱加載功能。

      tomcat主要類加載器:

      commonLoader:Tomcat最基本的類加載器,加載路徑中的class可以被Tomcat容器本身以及各個Webapp訪問;

      catalinaLoader:Tomcat容器私有的類加載器,加載路徑中的class對于Webapp不可見;

      sharedLoader:各個Webapp共享的類加載器,加載路徑中的class對于所有 Webapp可見,但是對于Tomcat容器不可見;

      WebappClassLoader:各個Webapp私有的類加載器,加載路徑中的class只對當前 Webapp可見,比如加載war包里相關的類,每個war包應用都有自己的WebappClassLoader,實現相互隔離,比如不同war包應用引入了不同的spring版本, 這樣實現就能加載各自的spring版本;

      注意:

      tomcat類加載機制違背了Java推薦的雙親加載機制。

      為了實現隔離性,沒有遵守Java推薦的雙親加載機制,,每個webappClassLoader加載自己的目錄下的class文件,不會傳遞給父類加載器,打破了雙親委派機制。

      模擬實現—>模擬實現Tomcat的webappClassLoader加載自己war包應用內不同版本類實現相互共存與隔離:

      代碼

      package com.zhz.bytecode; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author zhouhengzhe * @Description: 模擬實現Tomcat的webappClassLoader加載自己war包應用內不同版本類實現相互共存與隔 離 * @date 2021/9/22下午1:12 * @since */ public class SimulateTomcatMultipleVersionIsolation { static class CustomClassLoader extends ClassLoader { private String classpath; public CustomClassLoader(String classpath) { this.classpath = classpath; } /** * 重寫類加載方法,實現自己的加載邏輯,不委派給雙親加載 * @param name * @return: Class * @author: zhouhengzhe * @date: 2021/9/22 */ @Override public Class loadClass(String name,boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); //非自定義的類還是走雙親委派加載---->重要 if (!name.startsWith("com.zhz.jvm")){ c=this.getParent().loadClass(name); }else { c = findClass(name); } // this is the defining class loader; record the stats sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } if (resolve) { resolveClass(c); } return c; } } @Override protected Class findClass(String name) throws ClassNotFoundException { try { byte[] data = loadByte(name); //defineClass將一個字節數組轉為Class對象,這個字節數組是class文件讀取后最終的字節數組。 return defineClass(name,data,0,data.length); } catch (IOException e) { e.printStackTrace(); throw new ClassNotFoundException(); } } private byte[] loadByte(String name) throws IOException { //name = name.replaceAll("\.", "/"); FileInputStream fis = new FileInputStream(classpath + "/" + name + ".class"); int len = fis.available(); byte[] data = new byte[len]; fis.read(data); fis.close(); return data; } } public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //初始化自定義類加載器,會先初始化父類ClassLoader,其中會把自定義類加載器的父加載 器設置為應用程序類加載器AppClassLoader CustomClassLoaderTest.CustomClassLoader customClassLoader=new CustomClassLoaderTest.CustomClassLoader("D:/test"); //D盤創建 test/com/zhz/bytecode 幾級目錄,將User類的復制類User1.class丟入該目錄 Class clazz = customClassLoader.loadClass("com.zhz.jvm.User1"); Object instance = clazz.newInstance(); Method method = clazz.getDeclaredMethod("sout", null); method.invoke(instance,null); System.out.println(clazz.getClassLoader().getClass().getName()); //初始化自定義類加載器,會先初始化父類ClassLoader,其中會把自定義類加載器的父加載 器設置為應用程序類加載器AppClassLoader CustomClassLoaderTest.CustomClassLoader customClassLoader1=new CustomClassLoaderTest.CustomClassLoader("D:/test1"); //D盤創建 test/com/zhz/bytecode 幾級目錄,將User類的復制類User1.class丟入該目錄 Class clazz1 = customClassLoader1.loadClass("com.zhz.jvm.User1"); Object instance1 = clazz1.newInstance(); Method method1 = clazz1.getDeclaredMethod("sout", null); method1.invoke(instance1,null); System.out.println(clazz1.getClassLoader().getClass().getName()); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      JVM(5)——類加載機制

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      77

      78

      79

      80

      81

      82

      83

      84

      85

      86

      87

      88

      89

      90

      91

      92

      93

      94

      95

      96

      97

      98

      99

      100

      101

      注意:同一個JVM內,兩個相同包名和類名的類對象可以共存,因為他們的類加載器可以不一 樣,所以看兩個類對象是否是同一個,除了看類的包名和類名是否都相同之外,還需要他們的類加載器也是同一個才能認為他們是同一個。

      1.5、顯示當前ClassLoader加載了哪些Jar

      方法一:

      package com.zhz; import sun.misc.Launcher; import java.net.URL; /** * @author zhouhengzhe * @Description: 方法一:顯示當前ClassLoader加載了哪些Jar * @date 2021/9/12下午10:06 * @since */ public class TestJdkClassLoader { public static void main(String[] args) { System.out.println(String.class.getClassLoader()); System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader().getClass().getName()); System.out.println(TestJdkClassLoader.class.getClassLoader().getClass().getName()); System.out.println(); ClassLoader appClassLoader = ClassLoader.getSystemClassLoader(); ClassLoader extClassloader = appClassLoader.getParent(); ClassLoader bootstrapLoader = extClassloader.getParent(); System.out.println("the bootstrapLoader : " + bootstrapLoader); System.out.println("the extClassloader : " + extClassloader); System.out.println("the appClassLoader : " + appClassLoader); System.out.println(); System.out.println("bootstrapLoader加載以下文件:"); URL[] urls = Launcher.getBootstrapClassPath().getURLs(); for (int i = 0; i < urls.length; i++) { System.out.println(urls[i]); } System.out.println(); System.out.println("extClassloader加載以下文件:"); System.out.println(System.getProperty("java.ext.dirs")); System.out.println(); System.out.println("appClassLoader加載以下文件:"); System.out.println(System.getProperty("java.class.path")); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      方法二:

      package com.zhz.bytecode; import sun.misc.Launcher; import java.lang.reflect.Field; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Objects; /** * @author zhouhengzhe * @Description: 方法二:顯示當前ClassLoader加載了哪些Jar * @date 2021/9/18上午12:20 * @since */ public class JvmClassLoaderPrintPath { public static void main(String[] args) { //啟動類加載器 URL[] urLs = Launcher.getBootstrapClassPath().getURLs(); System.out.println("啟動類加載器"); for (URL urL : urLs) { System.out.println("==>"+ urL.toExternalForm()); } //擴展類加載器 printClassLoad("擴展類加載器",JvmClassLoaderPrintPath.class.getClassLoader()); //應用類加載器 printClassLoad("應用類加載器",JvmClassLoaderPrintPath.class.getClassLoader()); } private static void printClassLoad(String name, ClassLoader classLoader) { if (Objects.nonNull(classLoader)){ System.out.println(name+" ClassLoader -> "+classLoader.toString()); printURLForClassLoader(classLoader); return; } System.out.println(name+" ClassLoader -> null"); } private static void printURLForClassLoader(ClassLoader classLoader) { Object ucp = insightField(classLoader, "ucp"); Object path = insightField(ucp, "path"); ArrayList ps = (ArrayList) path; for (Object p : ps) { System.out.println(" ==> "+p.toString()); } } private static Object insightField(Object obj, String name){ try { Field field=null; if (obj instanceof URLClassLoader){ field=URLClassLoader.class.getDeclaredField(name); }else { field=obj.getClass().getDeclaredField(name); } field.setAccessible(true); return field.get(obj); }catch (Exception e){ e.printStackTrace(); return null; } } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      結果

      1.6、添加引用類的幾種方式

      1、放到 JDK 的 lib/ext 下,或者 -Djava.ext.dirs

      2、java-cp/classpath 或者 class 文件放到當前路徑

      3、自定義 ClassLoader 加載

      4、拿到當前執行類的 ClassLoader,反射調用 addUrl 方法添加 Jar 或路徑(JDK9 無效)

      Java JVM 容器

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:Excel做拼音田字格的具體操作方法
      下一篇:如何在Excel中的圖表中顯示隱藏數據
      相關文章
      亚洲日本香蕉视频| 亚洲伊人久久大香线蕉啊| 久久综合亚洲色HEZYO社区 | 色拍自拍亚洲综合图区| 亚洲国产一区二区三区| 在线观看亚洲免费| 爱情岛论坛亚洲品质自拍视频网站| 亚洲一本一道一区二区三区| 国产精品亚洲精品青青青| 亚洲国产福利精品一区二区| 亚洲另类视频在线观看| 亚洲天堂福利视频| 亚洲免费人成视频观看| 亚洲制服丝袜中文字幕| 91嫩草亚洲精品| 亚洲av乱码一区二区三区| 亚洲国产最大av| 一本天堂ⅴ无码亚洲道久久| 久久久久亚洲国产| 亚洲国产AV一区二区三区四区| 亚洲国产区男人本色| 亚洲a∨无码一区二区| 四虎亚洲国产成人久久精品| 亚洲精品无码专区久久同性男| 亚洲男人av香蕉爽爽爽爽| 国产亚洲精品拍拍拍拍拍| 夜夜春亚洲嫩草影院| 国产亚洲av片在线观看16女人| 久久精品亚洲日本佐佐木明希| 777亚洲精品乱码久久久久久| 亚洲精品中文字幕无乱码| 亚洲一区动漫卡通在线播放| 伊人久久五月丁香综合中文亚洲| 久久精品国产亚洲AV电影网| 亚洲av午夜成人片精品电影| 久久影院亚洲一区| 久久91亚洲精品中文字幕| 亚洲欧洲日产韩国在线| 亚洲中文字幕久久久一区| 青青青亚洲精品国产| 中文字幕亚洲综合久久菠萝蜜|