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

cassandra数据库入门-4

插入数据 在表中创建数据 您可以使用命令 INSERT 将数据插入表中一行的列中。 下面给出了在表中创建数据的语法。 INSERT INTO <tablename> (<column1 name>, <column2 name>....) VALUES (<value1>, <value2>....) USING <option> 例子…...

微服务学习——分布式搜索

初识elasticsearch 什么是elasticsearch elasticsearch是一款非常强大的开源搜索引擎&#xff0c;可以帮助我们从海量数据中快速找到需要的内容。 elasticsearch结合kibana、Logstash、Beats&#xff0c;也就是elastic stack(ELK)。被广泛应用在日志数据分析、实时监控等领域…...

ChatGPT根据销售数据、客户反馈、财务报告,自动生成报告,并根据不同利益方的需要和偏好进行调整?

该场景对应的关键词库&#xff08;24个&#xff09;&#xff1a; 汇报对象身份&#xff08;下属、跨部门平级、领导&#xff09;、销售数据&#xff08;销售额、销售量、销售渠道&#xff09;、财务报告&#xff08;营业收入、净利润、成本费用&#xff09;、市场分析&#xf…...

Flask开发之环境搭建

目录 1、安装flask 2、创建Flask工程 ​编辑 3、初始化效果 4、运行效果 5、设置Debug模式 6、设置Host 7、设置Port 8、在app.config中添加配置 1、安装flask 如果电脑上从没有安装过flask&#xff0c;则在命令行界面输入以下命令&#xff1a; pip install flask 如果电…...

Java集合框架与ArrayList、LinkedList的区别

文章目录 Java集合框架与ArrayList、LinkedList的区别集合框架ArrayList特点操作 LinkedList特点操作 区别代码实践注意事项 Java集合框架与ArrayList、LinkedList的区别 在Java中&#xff0c;集合框架是非常重要的一部分。集合框架提供了各种数据结构和算法&#xff0c;可以方…...

python-pandas库

目录 目录 目录 1.pandas库简介&#xff08;https://www.gairuo.com/p/pandas-overview&#xff09; 2.pandas库read_csv方法&#xff08;https://zhuanlan.zhihu.com/p/340441922?utm_mediumsocial&utm_oi27819925045248&#xff09; 1.pandas库简介&#xff08;http…...

C++学习day--01 C生万物

1、C/C学习中遇到的问题&#xff1a; 1. 大部分初学者&#xff0c;学习 C/C 都是从入门到放弃。 C/C太难吗&#xff1f; 2. 90% 以上的初学者&#xff0c;学完 C/C 以后&#xff0c;考试完了&#xff0c;书看完了&#xff0c; 但还是不会做项目 是学的不够好吗&#xff1…...

链表及链表的常见操作和用js封装一个链表

最近在学数据结构和算法&#xff0c;正好将学习的东西记录下来&#xff0c;我是跟着一个b站博主学习的&#xff0c;是使用js来进行讲解的&#xff0c;待会也会在文章后面附上视频链接地址&#xff0c;大家想学习的可以去看看 本文主要讲解单向链表&#xff0c;双向链表后续也会…...

源码安装工具checkinstall使用

每当从源码包编译程序时&#xff0c;安装过程很愉快&#xff0c;但当你想删除时&#xff0c;就很费脑筋了&#xff0c;你可能要去找你当时编译的目录执行make unistall&#xff0c;当然更可能的是&#xff0c;你早就把源码包给删除了&#xff0c;对于强迫症来说&#xff0c;这显…...

离散数学集合论

集合论 主要内容 集合基本概念 属于、包含幂集、空集文氏图等 集合的基本运算 并、交、补、差等 集合恒等式 集合运算的算律&#xff0c;恒等式的证明方法 集合的基本概念 集合的定义 集合没有明确的数学定义 理解&#xff1a;由离散个体构成的整体称为集合&#xff0c…...

进网站显示建设中怎么解决/长沙seo搜索

转自&#xff1a;http://www.cnblogs.com/daqiang/archive/2011/12/04/2275646.html STM32的定时器是个强大的模块&#xff0c;定时器使用的频率也是很高的&#xff0c;定时器可以做一些基本的定时&#xff0c;还可以做PWM输出或者输入捕获功能。 时钟源问题&#xff1a; 名…...

苏州知名高端网站建设企业/网站关键词排名seo

说天说地莫若说真&#xff0c;话东话西不如话实。 转载于:https://www.cnblogs.com/jiaoaozuoziji/p/7390236.html...

做试管网站/广东省广州市佛山市

XSS&#xff1a;脚本中的不速之客XSS&#xff1a;跨站脚本&#xff08;Cross-site scripting&#xff09;CSRF&#xff1a;冒充用户之手CSRF&#xff1a;跨站请求伪造&#xff08;Cross-site request forgery&#xff09; 谷歌搜索到几篇好文章。《XSS CSRF 攻击》http://www.c…...

wordpress git升级/网站推广的途径和方法

如果您只想使用CSS3&#xff0c;甚至不需要使用任何jQuery / Javascript。只需在您的CSS中执行此操作&#xff1a;.confirm_selection {-webkit-transition: text-shadow 0.2s linear;-moz-transition: text-shadow 0.2s linear;-ms-transition: text-shadow 0.2s linear;-o-tr…...

网站制作费用/百度发布平台官网

发现这不是一个省力的活。如果你的MySQL版本是5.1.7之后&#xff0c;并且是5.1.23之前&#xff0c;有一种简单的方法可以用&#xff1a;RENAME {DATABASE | SCHEMA} db_name TO new_db_name;但这种方法并不可靠&#xff0c;可能会造成数据的丢失&#xff0c;不建议使用。对此官…...

互联网公司是干啥的/seo网站的优化方案

TMemo组件属性 CaretPos 指定光标相对于编辑器的客户区域原点的X和Y的位置 当光标在TMemo组件上定位时&#xff0c;显示光标的坐标 panel1.Caption:当前位置&#xff1a;inttostr(Memo1.CaretPos.x),inttostr(Memo1.CaretPos.y); Lines 该属性以行为单位向文本编辑器添加或删除…...