一、sun.misc.Launcher (ExtClassLoader 与 AppClassLoader 的创建)

public Launcher() {
Launcher.ExtClassLoader var1;
try {
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
} try {
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
} Thread.currentThread().setContextClassLoader(this.loader);
String var2 = System.getProperty("java.security.manager");
if (var2 != null) {
SecurityManager var3 = null;
if (!"".equals(var2) && !"default".equals(var2)) {
try {
var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
} catch (IllegalAccessException var5) {
} catch (InstantiationException var6) {
} catch (ClassNotFoundException var7) {
} catch (ClassCastException var8) {
}
} else {
var3 = new SecurityManager();
} if (var3 == null) {
throw new InternalError("Could not create SecurityManager: " + var2);
}
System.setSecurityManager(var3);
}
}

二、自定义类加载器(继承 ClassLoader 类,重写 findClass 方法,不推荐重写 loadClass 方法,会破坏委派机制)

测试加载类,使用 javac 把 .java 文件编译成 .class 文件

package com;

public class Hello {
static {
System.out.println("Hello !");
} public void sayHi(String name){
System.out.println("Hello !" + name);
}
}

类加载器,注意要加载类的路径名与包名

package com;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method; public class ClassLoaderTest extends ClassLoader { private final static String filePathSuffix = ".class";
private String filePathPrefix; public ClassLoaderTest(String filePathPrefix) {
this.filePathPrefix = filePathPrefix;
} @Override
protected Class<?> findClass(String name) {
String fileName = name.split("\\.")[name.split("\\.").length - 1];
byte[] bytes = loadClassData(filePathPrefix + fileName + filePathSuffix);
return defineClass(name, bytes, 0, bytes.length);
} private byte[] loadClassData(String filePath) {
InputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(new File(filePath));
out = new ByteArrayOutputStream();
int i = 0;
while ((i = in.read()) != -1) {
out.write(i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return out.toByteArray();
} public static void main(String[] args) throws Exception {
ClassLoaderTest clt = new ClassLoaderTest("D:/");
Class c = clt.loadClass("com.Hello");
System.out.println(c.getClassLoader());
System.out.println(c.getClassLoader().getParent());
System.out.println(c.getClassLoader().getParent().getParent());
System.out.println(c.getClassLoader().getParent().getParent().getParent());
Method sayHi = c.getMethod("sayHi", String.class);
// 无参实例化
Object o = c.newInstance();
// 调用方法
sayHi.invoke(o, "zhangsan");
}
}

三、Class.forName() 和 ClassLoader.loadClass()

调用了 forName0,第二个参数为 true,默认会初始化,可使用其重载方法指定为 false

@CallerSensitive
public static Class<?> forName(String className) throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

调用了 loadClass 的重载方法,默认不会链接,就不会初始化了

public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}

以上面的 Hello 类为例,在 com 包下新建同样的文件,命名为 Hello1

public static void main(String[] args) throws Exception {
// 加载,链接,初始化
Class.forName("com.Hello1");
System.out.println("==========================================");
// 加载,链接
Class.forName("com.Hello1", false,ClassLoader.getSystemClassLoader());
System.out.println("==========================================");
// 加载
ClassLoader.getSystemClassLoader().loadClass("com.Hello1");
}

四、线程上下文类加载器(ThreadContextClassLoader)

https://mp.weixin.qq.com/s/4FJbRLUcg8FmOqP1uz3f2A

java.lang.Thread 中的方法 getContextClassLoader() 和 setContextClassLoader(ClassLoader cl) 用来获取和设置线程的上下文类加载器。

如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。

Java 应用运行的初始线程的上下文类加载器是系统类加载器。

Thread thread = new Thread(()->{
try {
Class<?> aClass = Thread.currentThread().getContextClassLoader().loadClass("com.Hello");
System.out.println(aClass.getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
});
thread.setContextClassLoader(new ClassLoaderTest("D:/"));
thread.start(); Thread.sleep(1000); thread = new Thread(()->{
try {
Class<?> aClass = Thread.currentThread().getContextClassLoader().loadClass("com.Hello1");
System.out.println(aClass.getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
});
thread.start();


https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.3.2

https://www.cnblogs.com/editice/p/5420712.html

最新文章

  1. .NET Core采用的全新配置系统[5]: 聊聊默认支持的各种配置源[内存变量,环境变量和命令行参数]
  2. Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)
  3. eclipse内嵌jetty(run-jetty-run插件) 配置jndi数据源
  4. MVVM架构~knockoutjs系列之扩展ajax验证~验证数据是否存在
  5. 2-Fedora 17系统安装准备
  6. gulp-notify处理报错----gulp系列(二)
  7. 在C#中使用官方驱动操作MongoDB ---转载
  8. windows开发hadoop文件系统权限错误
  9. Lua基础之语法
  10. 用javascript快速清空你的人人时间轴、状态和分享
  11. (重)POJ 3020Antenna Placement
  12. windows快捷键和命令
  13. Linux wget下载https类型文件报错解决方法 转自老左博客
  14. 关于asp:login控件和验证码的问题?(转)
  15. php中自动加载类_autoload()和spl_autoload_register()实例详解
  16. Ext JS 6开发实例(四) :调整主视图
  17. YARN简述
  18. 使用脚本调用maven命令后脚本直接退出问题
  19. [No0000D1]WPF—TreeView无限极绑定集合形成树结构
  20. 项目总结19:layui实现表格渲染、表格搜索、数据获取

热门文章

  1. 编译原理-递归下降分析法 c程序部分的分析
  2. mysql 中的 tinyint 字段
  3. Kivy 简单尝试
  4. Ubuntu .tar.xz文件解压缩命令
  5. cubase 的FX轨道使用方法
  6. 基于VS2017C++的窗口编写
  7. 认识并初步应用GitHub——C++
  8. LOAD DATA INFILE &amp; mysqlimport
  9. Vue双向绑定的实现原理系列(四):补充指令解析器compile
  10. 15-资源等待类型sys.dm_os_wait_stats