jvm之类加载器
写在前面
当我们通过javac命令将java源代码编译为Java字节码后,必须通过类加载器将其加载到jvm中才能运行,所以类加载器是jvm中非常重要的一个组成部分,本文我们就一起来看下吧!
1:类的生命周期
类的生命周期如下图:
注意以上包括卸载在内的所有过程都是通过类加载器完成的。
1.1:加载
将class字节码文件加载到jvm中,具体就是通过类加载器来完成的。class字节码本身的二进制信息会被加载到jvm的方法区中,并在堆中创建一个对应的java.lang.Class对象实例(java中万物皆对象,class字节码也不例外!)
,参考下图:
1.2:验证
首先通过魔法数字验证这是否是一个class字节码文件,java的class字节码使用前4个字节来进行标记cafebabe
,如下使用submit打开查看:
可以类比pdf文件的魔数是"%PDF",则其十六进制表示就是2550 4446
,如下图:
除了验证魔数之外,还会验证版本号,即class字节码文件可运行的jdk版本,如下就是版本53,即jdk1.9(52就是1.8,51就是1.7,50就是1.6,以此类推)
:
除了对于魔数和版本号的验证之外,还包括对字节码文件本身格式的验证等。
1.3:准备
为类的静态变量在方法区中分配内存,并给零值,即基础数据类型的默认值,如整型为0,布尔为false,具体如下:
假定有如下类:
class A {static int num1 = 90;staic boolean isOk = true;...
}
则经过准备阶段后如下图:
注意这个阶段并不会将num1赋值为程序中定义的90,isOK也不会赋值为程序中定义的true,而只是会给默认值,因为本步骤的主要是为静态变量们找到容身之所
,具体的赋值完成要等在初始化阶段完成。
1.4:解析
将常量池中的符号引用解析为实际引用,即将将使用到的类名称,如com.xx.A,解析为A类在方法区中的内存地址,这样当需要A类时就可以直接找到。所以解析就是将一个代表了某个信息的文本字符串转换为方法区中的某个内存地址。
1.5:初始化
执行构造器代码,执行静态代码块,为类静态变量赋值(还记得在准备阶段我们已经将类静态变量分配到方法去中内存并给默认值了吗?这里会给程序设置的实际值)
。如下代码就会在该阶段被执行:
class A {static {sout("静态代码块逻辑");}public A() {sout("构造函数逻辑");}static {sout("静态代码块逻辑");}
}
注意{}代码块不会被执行,因为代码块和普通类成员变量一样是属于类实例的,因此只有在创建类实例对象的时候才会执行。
2:类何时加载并初始化
2.1:运行main所在类
当我们通过main函数启动程序时,该main函数所在的会被加载并初始化,即如下操作:
2.2:new指令的目标类
当我们通过new关键字创建一个类实例对象时,该类对应的class字节码会被加载并初始化,如下:
2.3:invokestatic指令访问类静态方法
当调用某静态方法时,该静态方法所在的类会被初始化,如下:
2.4:getstatic指令访问静态类成员变量
当访问某静态变量时,该静态变量所在的类会被加载并初始化,如下:
2.5:子类的初始化会触发父类初始化
通过extends关键字继承的父类会随着本类的初始化而初始化,如下:
2.6:有default方法的接口子类初始化
当一个接口有default方法时,如果有其子类被初始化,则该接口也会被初始化,因为default方法是提供了具体实现的方法,是可以直接被子类使用的如下:
2.7:通过反射API创建某类实例时
这种情况通new指令,因为都是要创建对象实例,所以肯定是需要初始化的。
2.8:MethodHandle调用方法时
MethodHandle调用方法时,方法所在的类会被加载并初始化如下:
有些时候类会被加载但不会被初始化,接着来看下。
3:类何时加载但不初始化
3.1:通过子类引用父类的静态字段
因为此时只要能够访问到父类的静态就行了,并不需要子类初始化,如下操作:
- 定义类A,并定义静态变量
package yudaosourcecode.csdn.huohuo;public class A {static {System.out.println("A 初始化了");}static int num1 = 90;
}
- 定义A类的子类ASon
package yudaosourcecode.csdn.huohuo;public class ASon extends A {static {System.out.println("ASon 初始化了");}
}
- 定义B类通过ASon访问A的静态变量
package yudaosourcecode.csdn.huohuo;public class B {public static void main(String[] args) {System.out.println(ASon.num1);}
}
- 运行B输出如下
可以看到A类初始化了,ASon并没有初始化。
3.2:定义对象数组不会触发该类的初始化
因为此时只需要保证jvm中有该类的class即可,还没有使用,所以不会初始化,如下测试:
- 定义类A
package yudaosourcecode.csdn.huohuo;public class A {static {System.out.println("A 初始化了");}static int num1 = 90;
}
- 定义类B,在其中定义A数组
package yudaosourcecode.csdn.huohuo;public class B {public static void main(String[] args) {A[] as = {};}
}
运行,不会看到A 初始化了
说明A并没有初始化:
3.3:应用某类的常量不会初始化该类
因为这种方式在编译时就是将常量值存入到常量池中,所以并不需要常量所在类初始化,如下:
- 定义类A并定义常量
package yudaosourcecode.csdn.huohuo;public class A {final static String name = "jack";static {System.out.println("A 初始化了");}static int num1 = 90;
}
- 定义类B并访问A的常量
package yudaosourcecode.csdn.huohuo;public class B {public static void main(String[] args) {System.out.println(A.name);}
}
运行,A并没有初始化,如下:
因为常量是不能在运行期被更改的,所以可以在编译器直接存入方法区中的常量池中,而不需要动态获取,但是普通静态变量不同,静态变量是可以程序运行的过程中被修改的,所以访问静态变量会导致静态变量所在类的初始化。
3.4:通过.class获取类的Class对象不会导致初始化
因为class字节码的Class对象在加载
阶段就已经创建完毕并分配到堆上了,所以并不会进行初始化。如下:
- 定义A类
package yudaosourcecode.csdn.huohuo;public class A {final static String name = "jack";static {System.out.println("A 初始化了");}static int num1 = 90;
}
- 定义B类,访问A类的class对象
package yudaosourcecode.csdn.huohuo;public class B {public static void main(String[] args) {System.out.println(A.class);}
}
访问测试,A并没有初始化:
3.5:Class.forName设置initialize false不会初始化
initialize参数使用来告诉虚拟机是否要初始化指定类,false不初始化,true初始化,如下:
- 定义A类
package yudaosourcecode.csdn.huohuo;public class A {static {System.out.println("A 初始化了");}static int num1 = 90;
}
- 定义B类,initialize设置为false
package yudaosourcecode.csdn.huohuo;public class B {public static void main(String[] args) throws Exception {Class.forName("yudaosourcecode.csdn.huohuo.A", false, B.class.getClassLoader());}
}
运行:
可以看到A类并没有初始化。
如果使用 Class.forName("yudaosourcecode.csdn.huohuo.A");
,此时initialize默认为true,则会初始化A类,如下:
3.6:通过ClassLoader的loadClass
通过ClassLoader的loadClass也是只会加载而不会初始化。如下:
- 定义A类
package yudaosourcecode.csdn.huohuo;public class A {static {System.out.println("A 初始化了");}static int num1 = 90;
}
- 定义B类使用类加载器加载A类
package yudaosourcecode.csdn.huohuo;public class B {public static void main(String[] args) throws Exception {B.class.getClassLoader().loadClass("yudaosourcecode.csdn.huohuo.A");}
}
运行:
4:3种类加载器
4.1:3种类加载器以及其特点
三种类加载器分别是启动类加载器BootstrapClassLoader,扩展类加载器ExtClassLoader,应用类加载器AppCLassLoader,其职责如下:
启动类加载器BootstrapClassLoader:负责加载jre核心类库,如jre/lib/rt.jar
扩展类加载器ExtClassLoader:负责加载lib/ext,或者java.ext.dirs指定目录的jar和class
应用类加载器AppClassLoader:负责加载-classpath,-cp,java.class.path属性指定的类路径
特点如下:
双亲委派:当需要根据类全限定名称加载某个class时,并不会自己直接加载,而是先找其父类加载器加载,当最终也没有加载类时则会报出ClassNotFoundException
负责依赖:当加载的类,依赖于其它类时,也会加载这些依赖的类
加载缓存:已经加载的类会进行缓存,避免重复加载
其中还有第四种类加载器,就是自定义的类加载器,如下图:
4.2:自定义类加载器
假定我们现在有这样的一个需求,有一个类机密程度非常高,其.class字节码文件不能暴露出去,因为一旦暴露出去就可以很容易的通过反编译工具,甚至是通过javap来读指令,获取源码信息,这个时候普通的类加载器就无法满足需求了,我们就需要来自定义类加载器,该类加载器可以加载一个.class加密后的字符串来加载类,简单起见,我们就用base64来模拟加密后的.class字节码,则假定我们有如下的类:
package yudaosourcecode.csdn.huohuo;public class A {static {System.out.println("A 初始化了");}
}
接着我们执行如下操作,获取类对应字节码的加密结果这里是base64
:
bogon:huohuo xb$ javac -d . A.java
bogon:huohuo xb$ java yudaosourcecode/csdn/huohuo/A
A 初始化了
bogon:huohuo xb$ base64 yudaosourcecode/csdn/huohuo/A.class
yv66vgAAADUAHgoABgAQCQARABIIABMKABQAFQcAFgcAFwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEACDxjbGluaXQ+AQAKU291cmNlRmlsZQEABkEuamF2YQwABwAIBwAYDAAZABoBAA5BIOWIneWni+WMluS6hgcAGwwAHAAdAQAdeXVkYW9zb3VyY2Vjb2RlL2NzZG4vaHVvaHVvL0EBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAAwAJAAsADAABAAkAAAAZAAAAAQAAAAGxAAAAAQAKAAAABgABAAAACQAIAA0ACAABAAkAAAAlAAIAAAAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAFAAgABgABAA4AAAACAA8=
这里的base64后的结果我们就可以在自定义类加载器中使用了,自定义类加载器如下:
package yudaosourcecode.csdn.huohuo;import java.util.Base64;public class ACLassLoader extends ClassLoader {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {String helloBase64 = "yv66vgAAADUAHgoABgAQCQARABIIABMKABQAFQcAFgcAFwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEACDxjbGluaXQ+AQAKU291cmNlRmlsZQEABkEuamF2YQwABwAIBwAYDAAZABoBAA5BIOWIneWni+WMluS6hgcAGwwAHAAdAQAdeXVkYW9zb3VyY2Vjb2RlL2NzZG4vaHVvaHVvL0EBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAAwAJAAsADAABAAkAAAAZAAAAAQAAAAGxAAAAAQAKAAAABgABAAAACQAIAA0ACAABAAkAAAAlAAIAAAAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAAFAAgABgABAA4AAAACAA8=";byte[] bytes = decode(helloBase64);return defineClass(name,bytes,0,bytes.length);}public byte[] decode(String base64){return Base64.getDecoder().decode(base64);}
}
然后使用自定义类加载器加载我们的加密类
:
package yudaosourcecode.csdn.huohuo;public class B {public static void main(String[] args) throws Exception {new ACLassLoader().loadClass("yudaosourcecode.csdn.huohuo.A").newInstance();}
}
运行:
5:利用类加载器帮我们排查问题
5.1:找不到jar包
在工作中经常遇到这样问题,明明jar包已经加到classpath中,但就是找不到,这个时候我们能不能明确的获取各种类加载器加载了哪些jar包和class,从而定位问题呢?是可以的,定义如下类:
package yudaosourcecode.csdn.huohuo;import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;public class A {public static void main(String[] args) {// 启动类加载器URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();System.out.println("启动类加载器");for (URL url : urls) {System.out.println(" ==> " + url.toExternalForm());}// 扩展类加载器printClassLoader("扩展类加载器", A.class.getClassLoader().getParent());// 应用类加载器printClassLoader("应用类加载器", A.class.getClassLoader());}public static void printClassLoader(String name, ClassLoader CL) {if (CL != null) {System.out.println(name + " ClassLoader ‐> " + CL.toString());printURLForClassLoader(CL);} else {System.out.println(name + " ClassLoader ‐> null");}}public static void printURLForClassLoader(ClassLoader CL) {Object ucp = insightField(CL, "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 fName) {try {Field f = null;if (obj instanceof URLClassLoader) {f = URLClassLoader.class.getDeclaredField(fName);} else {f = obj.getClass().getDeclaredField(fName);}f.setAccessible(true);return f.get(obj);} catch (Exception e) {e.printStackTrace();return null;}}
}
运行,注意使用jdk8:
bogon:huohuo xb$ /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/bin/javac -d . A.java
A.java:11: 警告: Launcher是内部专用 API, 可能会在未来发行版中删除URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();^
1 个警告
bogon:huohuo xb$ /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/bin/java yudaosourcecode/csdn/huohuo/A
启动类加载器==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/resources.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/sunrsasign.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/jsse.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/jce.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/charsets.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/jfr.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/classes
扩展类加载器 ClassLoader ‐> sun.misc.Launcher$ExtClassLoader@7852e922==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/ext/sunec.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/ext/nashorn.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/ext/cldrdata.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/ext/jfxrt.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/ext/dnsns.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/ext/localedata.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/ext/jaccess.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/ext/zipfs.jar==> file:/System/Library/Java/Extensions/MRJToolkit.jar
应用类加载器 ClassLoader ‐> sun.misc.Launcher$AppClassLoader@2a139a55==> file:/Users/xb/Desktop/D/dongsir-dev/java-life-current/java-life/src/main/java/yudaosourcecode/csdn/huohuo/
可以很清晰的看到启动类加载器,扩展类加载器,应用类加载器都加载了哪些jar和class。
5.2:NoSuchMethodError
如果是通过5.1:找不到jar包
确定jar包肯定加载了,则就要看下是不是加载了不同版本的jar,即jar冲突了,一般是这个原因。
5.3:如何看类加载顺序
5.2:NoSuchMethodError
如果是因为冲突造成的,则可以通过这里的方法来进一步定位问题,需要在java命令中增加‐XX:+TraceClassLoading 或者 ‐verbose 即可,如下:
bogon:huohuo xb$ /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/bin/java -XX:+TraceClassLoading yudaosourcecode/csdn/huohuo/A
[Opened /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Object from /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.io.Serializable from /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Comparable from /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.CharSequence from /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.String from /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.reflect.AnnotatedElement from /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar]
...
5.4:怎么修改启动类加载器和扩展类加载器加载内容
正常的,我们只需要rt.jar就行了,但默认的启动类加载器会加载很多其它的jar,此时可以通过‐Dsun.boot.class.path
来指定要加载的jar,如下:
bogon:huohuo xb$ /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/bin/java -Dsun.boot.class.path="/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar" yudaosourcecode/csdn/huohuo/A
启动类加载器==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar
扩展类加载器 ClassLoader ‐> sun.misc.Launcher$ExtClassLoader@7852e922==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/ext/sunec.jar...
可以看到此时启动类加载器只加载了rt.jar,对于扩展类加载器,正常其默认加载的jar包我们都是使用不到的,所以可以通过‐Djava.ext.dirs将其设置为空,即不加载,如下:
bogon:huohuo xb$ /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/bin/java -Djava.ext.dirs="" yudaosourcecode/csdn/huohuo/A
启动类加载器==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/resources.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/rt.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/sunrsasign.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/jsse.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/jce.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/charsets.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/lib/jfr.jar==> file:/Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/jre/classes
扩展类加载器 ClassLoader ‐> sun.misc.Launcher$ExtClassLoader@15db9742
应用类加载器 ClassLoader ‐> sun.misc.Launcher$AppClassLoader@73d16e93==> file:/Users/xb/Desktop/D/dongsir-dev/java-life-current/java-life/src/main/java/yudaosourcecode/csdn/huohuo/
此时扩展类加载器就什么都不加载了。
5.5:运行时动态加载类
有两种方式,第一种是通过自定义类加载器,第二种是通过URLClassLoader的addURL方法动态添加应用类加载器加载类时的扫描路径,分别看下。
5.5.1:自定义类加载器
- 定义要动态加载的类A
package yudaosourcecode.csdn.huohuo;public class A {static {System.out.println("A初始化了!");}public static void main(String[] args) {}}
- 定义自定义类类加载器
package yudaosourcecode.csdn.huohuo;import sun.misc.BASE64Encoder;import java.io.File;
import java.io.FileInputStream;
import java.util.Base64;public class ACLassLoader extends ClassLoader {@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {// 这里的路径注意修改为自己的!!!String path = "/Users/xb/Desktop/D/dongsir-dev/java-life-current/java-life/src/main/java/yudaosourcecode/csdn/huohuo/yudaosourcecode/csdn/huohuo/A.class";File file = new File(path);byte[] byte1 = new byte[0];try (FileInputStream fis = new FileInputStream(file)) {byte1 = new byte[fis.available()];fis.read(byte1);} catch (Exception e) {}BASE64Encoder encoder = new BASE64Encoder();String helloBase64 = encoder.encode(byte1);helloBase64 = helloBase64.replaceAll("\n", "");byte[] bytes = decode(helloBase64);return defineClass(name,bytes,0,bytes.length);}public byte[] decode(String base64){return Base64.getDecoder().decode(base64);}
}
- 定义测试类
package yudaosourcecode.csdn.huohuo;public class LoadDynamic {public static void main(String[] args) throws Exception {new ACLassLoader().loadClass("yudaosourcecode.csdn.huohuo.A").newInstance();}
}
- 运行
注意用java8
bogon:huohuo xb$ /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/bin/javac -d . A.java
bogon:huohuo xb$ /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/bin/javac -d . ACLassLoader.java
ACLassLoader.java:3: 警告: BASE64Encoder是内部专用 API, 可能会在未来发行版中删除
import sun.misc.BASE64Encoder;^
ACLassLoader.java:19: 警告: BASE64Encoder是内部专用 API, 可能会在未来发行版中删除BASE64Encoder encoder = new BASE64Encoder();^
ACLassLoader.java:19: 警告: BASE64Encoder是内部专用 API, 可能会在未来发行版中删除BASE64Encoder encoder = new BASE64Encoder();^
3 个警告
bogon:huohuo xb$ /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/bin/javac -d . LoadDynamic.java
bogon:huohuo xb$ /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home/bin/java yudaosourcecode/csdn/huohuo/LoadDynamic
A初始化了!
可以看到A类初始化了。
5.5.2:URLClassLoader的addUrl方法
定义如下类:
package yudaosourcecode.csdn.huohuo;import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;public class B {public static void main(String[] args) throws Exception {// 注意修改为自己本地的路径String appPath = "file:/Users/xb/Desktop/D/dongsir-dev/java-life-current/java-life/src/main/java/yudaosourcecode/csdn/huohuo/yudaosourcecode/csdn/huohuo";URLClassLoader urlClassLoader = (URLClassLoader) B.class.getClassLoader();try {Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);// 暴力访问addURL.setAccessible(true);URL url = new URL(appPath);addURL.invoke(urlClassLoader, url);// 动态加载A类Class.forName("yudaosourcecode.csdn.huohuo.A");} catch (Exception e) {e.printStackTrace();}}
}
运行:
...
[INFO] --- exec-maven-plugin:3.0.0:exec (default-cli) @ java ---
A初始化了!
[INFO]
...
写在后面
详解java类的生命周期 。
文件类型识别----魔数 。
一个类的生命周期 。
相关文章:

jvm之类加载器
写在前面 当我们通过javac命令将java源代码编译为Java字节码后,必须通过类加载器将其加载到jvm中才能运行,所以类加载器是jvm中非常重要的一个组成部分,本文我们就一起来看下吧! 1:类的生命周期 类的生命周期如下图…...

Chapter4:频率响应法(上)
第四章:频率响应法 Exercise4.1 已知微分网络和积分网络电路图如下图所示,求网络的频率特性。 解: 【图 ( a ) ({\rm a}) (a)微分网络】 由微分网络电路图可得:...

【6. 激光雷达接入ROS】
欢迎大家阅读2345VOR的博客【6. 激光雷达接入ROS】🥳🥳🥳 2345VOR鹏鹏主页: 已获得CSDN《嵌入式领域优质创作者》称号👻👻👻,座右铭:脚踏实地,仰望星空&#…...

Java 基础进阶篇(三)—— 面向对象的三大特征之二:继承
文章目录 一、继承概述二、内存运行原理 ★三、继承的特点四、继承后:成员变量和方法的访问特点五、继承后:方法重写六、继承后:子类构造器的特点七、继承后:子类构造器访问父类有参构造器八、this、super 总结 一、继承概述 Jav…...
[angstromctf 2023] 部分
这个比赛打了个开头就放弃了,最近放弃的比较多,国外的网太慢,国内的题太难。 Crypto ranch 这题直接给出密文这提示 rtkw{cf0bj_czbv_nvcc_y4mv_kf_kip_re0kyvi_uivjj1ex_5vw89s3r44901831} Caesar dressing is so 44 BC... 然后是加密程序…...

死信队列
死信队列 死信的概念 先从概念解释上搞清楚这个定义,死信,顾名思义就是无法被消费的消息,字面意思可以这样理解,一般来说,producer 将消息投递到 broker 或者直接到queue 里了,consumer 从 queue 取出消息…...

基于YOLOv5的目标检测系统详解(附MATLAB GUI版代码)
摘要:本文重点介绍了基于YOLOv5目标检测系统的MATLAB实现,用于智能检测物体种类并记录和保存结果,对各种物体检测结果可视化,提高目标识别的便捷性和准确性。本文详细阐述了目标检测系统的原理,并给出MATLAB的实现代码…...

使用ChatGPT工具阅读文献的实战教程
大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…...
实训笔记1
实训笔记 第一天 1.安装tomcat或者其他大数据开发的路径不含中文及空格 2.和同开发 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FoApp1oX-1683039421826)(C:\Users\18249\AppData\Roaming\Typora\typora-user-images\image-20230422110823748…...

CCD视觉检测设备如何选择光源
CCD视觉检测设备的机器视觉系统对光源的要求很高,光源是决定图像质量的一个重要因素。那么,我们就来看看CCD图像加网设备和机器视觉系统光源的选择点——CCD图像加网设备。 CCD视觉检测设备机器视觉系统光源选择要点: 1. 对比度:…...

基于协同过滤的旅游推荐系统设计与实现(论文+源码)_kaic
1 绪论 1.1 研究背景及意义 1.2 国内外研究现状 1.3 研究目标与意义 1.4 主要研究工作 2 相关理论介绍 2.1HTML与JavaScript 2.2 MySQL数据库 2.3 协同过滤算法简介 3 系统分析与设计 3.1 系统需求分析 3.1.1 功能性需求 3.1.2 安全性需求 3.2 系统总体架构 3.3 功能模块设计 3…...
代码随想录补打卡 746 使用最小花费爬楼梯
代码如下 func minCostClimbingStairs(cost []int) int { dp : make([]int,len(cost)1) //思路:设置一个花费数组dp,dp数组的长度等于之前的cost在加上1(1为楼顶元素) dp[0] 0 dp[1] 0 for i : 2 ; i < len(c…...
有理函数的不定积分习题
前置知识:有理函数的不定积分 习题 计算 ∫ x 3 1 x 4 − 3 x 3 3 x 2 − x d x \int \dfrac{x^31}{x^4-3x^33x^2-x}dx ∫x4−3x33x2−xx31dx 解: \qquad 将被积函数的分母因式分解得 x 4 − 3 x 3 3 x 2 − x x ( x − 1 ) 3 x^4-3x^33x^2-xx…...

PS滤镜插件-Nik Collection介绍
PS滤镜插件-Nik Collection介绍 什么是Nik CollectionNik Collection都包含什么? 什么是Nik Collection Nik Collection是一款PS滤镜插件套装,其包含了八款PS插件,功能涵盖修图、调色、降噪、胶片滤镜等方面。Nik Collection 作为很多摄影师…...

力扣刷题2023-05-04-1——题目:2614. 对角线上的质数
题目: 给你一个下标从 0 开始的二维整数数组 nums 。 返回位于 nums 至少一条 对角线 上的最大 质数 。如果任一对角线上均不存在质数,返回 0 。 注意: 如果某个整数大于 1 ,且不存在除 1 和自身之外的正整数因子,…...

【Java笔试强训 2】
🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🤺🤺🤺 目录 一、选择题 二、编程题 🔥排序子…...

术数基础背诵口诀整理
物象对应 五行方位天干神兽季节气候星宿生成数脏器木东甲乙青龙春风岁八肝火南丙丁朱雀夏热荧惑七心土中戊己?长夏湿镇五脾金西庚辛白虎秋燥太白九肺水北壬癸玄武冬寒辰六肾 口诀:东方甲乙青龙木,南方丙丁朱雀火,戊己勾陈腾蛇土&…...

Linux 基础语法 -2
如果我们以后再Linux当中 写了一些命名,导致程序我们不能进行操作了,如这个死循环: 他就会一直输出 "hello Linux" ,我们就使用 ctrl c 来终止因为程序或者指令异常,而导致我们无法进行指令输入ÿ…...

深度学习框架发展趋势
深度学习方法的发展是推动深度学习框架进步的最大动力,因此深度学习框架的功能和设计应顺应 算法和模型的发展趋势: 第一,易用性。深度学习领域仍处于快速发展期,参与者和学习者不断增加,新模型大量提出。因 此&#…...

Mysql为json字段创建索引的两种方式
目录 一、前言二、通过虚拟列添加索引(Secondary Indexes and Generated Columns)三、多值索引(Using multi-valued Indexes)四、官网地址 一、前言 JSON 数据类型是在mysql5.7版本后新增的,同 TEXT,BLOB …...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...