三种方法的任意类加载

第一种方法

使用URLClassLoder类进行任意类加载,具体实现如下:

1
2
3
4
5
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:///D:\\tmp\\")});//http也是可以的
Class<?> c = urlClassLoader.loadClass("test");
c.newInstance();

//URLClassLoader 任意类加载

第二种方法

使用ClassLoader里的defineClass方法

1
2
3
4
5
6
7
8
9
10
//不用出网
ClassLoader cl = ClassLoader.getSystemClassLoader();

Method cname = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
cname.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("D:\\tmp\\test.class")); //将 D:\tmp\test.class 这个文件的全部内容读取到一个字节数组 code 中。
Class cc = (Class) cname.invoke(cl,"test",code,0,code.length);//第三个参数是起始位置,返回的是test类的Class对象,类型是object要强转为Class(类的元数据对象)

cc.newInstance();
//defineclass 任意类加载

第三种方法

使用unsafe里的defineClass方法

img

主要是这边获取到属性theUnsafe的值就得到了实列化的Unsafe可以任意调用方法。

1
2
3
4
5
6
7
8
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class c = Unsafe.class;
Field f = c.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null); //获取值 new Unsafe()
byte[] code = Files.readAllBytes(Paths.get("D:\\tmp\\test.class"));
Class u = unsafe.defineClass("test",code,0,code.length,cl,null);
u.newInstance();