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

江西省建设工程安全质量监督管理局网站搜外友链平台

江西省建设工程安全质量监督管理局网站,搜外友链平台,免费网站建设 优帮云,查询网站dns服务器写在前面 当我们通过javac命令将java源代码编译为Java字节码后,必须通过类加载器将其加载到jvm中才能运行,所以类加载器是jvm中非常重要的一个组成部分,本文我们就一起来看下吧! 1:类的生命周期 类的生命周期如下图…

写在前面

当我们通过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类的生命周期 。

文件类型识别----魔数 。

一个类的生命周期 。

http://www.hengruixuexiao.com/news/17066.html

相关文章:

  • 设计网站首页12345网址大全下载到桌面
  • 个人想做企业网站备案百度首页清爽版
  • 南宁品牌网站建设医院线上预约
  • 什么是软件外包产业优化seo是什么意思
  • 怎么做网站拍卖的那种免费下载app并安装
  • 2014网站备案2345王牌浏览器
  • 零售网站模板网站优化怎么做
  • 东莞专业的网站设计价格关键词网络推广企业
  • 东莞手机网站价格表搜索引擎广告案例
  • 店面门头设计网站搜索引擎优化的简称
  • 网站建设南阳百度首页百度
  • 西安有一个电影他要拉投资做网站安徽网站推广
  • 网站的描述 都应该写 什么 优化搜了网推广效果怎么样
  • 西宁高端网站建设公司重庆百度地图
  • 什么是伪静态网站成都网络营销公司
  • wap端和app有什么区别广州seo推广
  • 搜索引擎的网站推广方式seo优化多少钱
  • 网站后台管理系统有哪些企业网站官网
  • python官网下载安装搜索引擎排名优化
  • 河南锦路路桥建设有限公司网站如何制作网站免费建站
  • so导航 抖音seo搜索如何优化
  • 福州网站设计费用电商培训大概多少学费
  • 中国建设银行曲江支行网站百度广告投放
  • 网站代运营推广百度客服平台
  • 王串场街网站建设公司海外独立站
  • 一个做问卷调查的网站上海网站建设开发
  • 做自己的彩票网站石家庄seo推广优化
  • 外贸网站建设及优化ppt模块东营seo整站优化
  • php做网站视频播放下载功能有哪些免费网站可以发布广告
  • wordpress加密访问株洲seo推广