excel表格里面画斜线方法
732
2022-05-28
文章目录
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
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小时内删除侵权内容。