当前位置: 首页 > news >正文

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字节码后&#xff0c;必须通过类加载器将其加载到jvm中才能运行&#xff0c;所以类加载器是jvm中非常重要的一个组成部分&#xff0c;本文我们就一起来看下吧&#xff01; 1&#xff1a;类的生命周期 类的生命周期如下图…...

Chapter4:频率响应法(上)

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

【6. 激光雷达接入ROS】

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

Java 基础进阶篇(三)—— 面向对象的三大特征之二:继承

文章目录 一、继承概述二、内存运行原理 ★三、继承的特点四、继承后&#xff1a;成员变量和方法的访问特点五、继承后&#xff1a;方法重写六、继承后&#xff1a;子类构造器的特点七、继承后&#xff1a;子类构造器访问父类有参构造器八、this、super 总结 一、继承概述 Jav…...

[angstromctf 2023] 部分

这个比赛打了个开头就放弃了&#xff0c;最近放弃的比较多&#xff0c;国外的网太慢&#xff0c;国内的题太难。 Crypto ranch 这题直接给出密文这提示 rtkw{cf0bj_czbv_nvcc_y4mv_kf_kip_re0kyvi_uivjj1ex_5vw89s3r44901831} Caesar dressing is so 44 BC... 然后是加密程序…...

死信队列

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

基于YOLOv5的目标检测系统详解(附MATLAB GUI版代码)

摘要&#xff1a;本文重点介绍了基于YOLOv5目标检测系统的MATLAB实现&#xff0c;用于智能检测物体种类并记录和保存结果&#xff0c;对各种物体检测结果可视化&#xff0c;提高目标识别的便捷性和准确性。本文详细阐述了目标检测系统的原理&#xff0c;并给出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视觉检测设备的机器视觉系统对光源的要求很高&#xff0c;光源是决定图像质量的一个重要因素。那么&#xff0c;我们就来看看CCD图像加网设备和机器视觉系统光源的选择点——CCD图像加网设备。 CCD视觉检测设备机器视觉系统光源选择要点&#xff1a; 1. 对比度&#xff1a;…...

基于协同过滤的旅游推荐系统设计与实现(论文+源码)_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) //思路&#xff1a;设置一个花费数组dp&#xff0c;dp数组的长度等于之前的cost在加上1&#xff08;1为楼顶元素&#xff09; dp[0] 0 dp[1] 0 for i : 2 ; i < len(c…...

有理函数的不定积分习题

前置知识&#xff1a;有理函数的不定积分 习题 计算 ∫ 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−xx31​dx 解&#xff1a; \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都包含什么&#xff1f; 什么是Nik Collection Nik Collection是一款PS滤镜插件套装&#xff0c;其包含了八款PS插件&#xff0c;功能涵盖修图、调色、降噪、胶片滤镜等方面。Nik Collection 作为很多摄影师…...

力扣刷题2023-05-04-1——题目:2614. 对角线上的质数

题目&#xff1a; 给你一个下标从 0 开始的二维整数数组 nums 。 返回位于 nums 至少一条 对角线 上的最大 质数 。如果任一对角线上均不存在质数&#xff0c;返回 0 。 注意&#xff1a; 如果某个整数大于 1 &#xff0c;且不存在除 1 和自身之外的正整数因子&#xff0c;…...

【Java笔试强训 2】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;排序子…...

术数基础背诵口诀整理

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

Linux 基础语法 -2

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

深度学习框架发展趋势

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

Mysql为json字段创建索引的两种方式

目录 一、前言二、通过虚拟列添加索引&#xff08;Secondary Indexes and Generated Columns&#xff09;三、多值索引&#xff08;Using multi-valued Indexes&#xff09;四、官网地址 一、前言 JSON 数据类型是在mysql5.7版本后新增的&#xff0c;同 TEXT&#xff0c;BLOB …...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...