当前位置: 首页 > 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 …...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...