大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
package com.tech.load.def;
/**
* @author lw
* @since 2021/12/3
*/
public class UserImpl {
static {
System.out.println("UserImpl init ...");
}
}
package com.tech.load.def;
/**
* @author lw
* @since 2021/12/3
*/
public class DefLoader {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//上下文类加载器,默认使用的是 应用程序类加载器
// ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
// Class<?> c1 = contextClassLoader.loadClass("com.tech.load.def.UserImpl");
// c1.newInstance(); //classloader.loadClass 不会触发初始化,当创建对象时执行初始化,执行静态程序块内容 输出 "UserImpl init ..."
// ClassLoader contextClassLoader1 = Thread.currentThread().getContextClassLoader();
// Class<?> c2 = contextClassLoader1.loadClass("com.tech.load.def.UserImpl");
// c2.newInstance(); //使用相同的类加载器 加载相同的类名 则加载的是同一个类,c1 c2是同一个类,由于已经初始化过 创建对象不再初始化 不再打印 "UserImpl init ..."
// System.out.println(contextClassLoader==contextClassLoader1); //true 获取的上下文类加载器是同一个类加载器
// System.out.println(c1==c2); // true 同一个类加载器器,加载同名的类,第一次加载时加载的类会缓存到类加载器的缓存,再次加载直接在缓存读取,两次加载的是同一个类
//直接获取类的类加载器 应用程序类加载器
ClassLoader classLoader = UserImpl.class.getClassLoader();
ClassLoader classLoader1 = UserImpl.class.getClassLoader();
System.out.println(classLoader==classLoader1); //true 获取的是同一个应用程序类加载器
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
System.out.println(classLoader==contextClassLoader); //true 线程上下文类加载器默认采用的也是应用程序类加载器 与通过类型对象getClassLoader获取方式相同
Class<?> c1 = Class.forName("com.tech.load.def.UserImpl"); //会触发类的初始化
ClassLoader classLoader2 = c1.getClassLoader();
System.out.println(classLoader==classLoader2); //true 获取的是同一个应用程序类加载器
}
}
在应用程序中,默认我们获取上下文类加载器、类型对象getClassLoader都是采用的同一个应用程序类加载器,类在第一次被加载后会缓存到类加载器的缓存中,由于是同一个类加载器此时同名的类不能被多次加载,且应用程序类加载器只能加载classpath下的类。
如果我们想加载自定义路径下的类,需要用到自定义类加载器,可以去指定路径下加载类,且通过创建多个类加载器对象,加载的同名类相互隔离,也就是说同名类可以被多个自定义类加载器对象加载。
编写自定义类加载器:
- 继承ClassLoader;
- 重写findClass方法在指定路径下进行类的加载,得到字节数组,然后使用defineClass根据字节数组生成字节码文件 也就是class文件;
编写一个测试类Goods放在D盘下,javac得到class文件
/**
* @author lw
* @since 2021/12/3
*/
public class Goods {
static {
System.out.println("Goods init ...");
}
}
javac Goods.java
package com.tech.load.def;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
* 自定义类加载器 加载类
* @author lw
* @since 2021/12/3
*/
public class DefLoad7 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
MyClassLoader classLoader1 = new MyClassLoader();
Class<?> c1 = classLoader1.loadClass("Goods");
Class<?> c2 = classLoader1.loadClass("Goods");
System.out.println(c1==c2);//true 使用同一个类加载器加载同名类两次,实际只加载了一次,第二次是在类加载器的缓存加载的 结果两次加载的是同一个
c1.newInstance(); //会初始化
c2.newInstance(); //不会初始化
MyClassLoader classLoader2 = new MyClassLoader();
Class<?> c3 = classLoader2.loadClass("Goods");
System.out.println(c1==c3); //false 使用不同的类加载器对同一个类进行加载,会得到不同的类型对象
c3.newInstance(); //会初始化
}
}
//自定义类加载器 加载D盘下的类
class MyClassLoader extends ClassLoader{
//去指定的路径下加载类
//name是类名称
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String path="D:\\"+name+".class";
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
//将指定路径下的文件 拷贝到输出流
Files.copy(Paths.get(path),os);
byte[] bytes = os.toByteArray();
//调用父类的方法 根据字节数组生成字节码文件 也就是class文件
//bytes -> *.class
return defineClass(name,bytes,0,bytes.length);
} catch (IOException e) {
e.printStackTrace();
throw new ClassNotFoundException("类文件未找到",e);
}
}
}
使用自定义加载器,创建多个类加载器对象去加载同一个类,会得到多个类型对象。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/196882.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...