我正在尝试使用 Java 的 sun.misc.Unsafe.defineClass(String name, byte[] code, int off, int len, ClassLoader classLoader, ProtectionDomain protectionDomain( 动态加载类,但由于某种原因,我通过调用 Class.newInstance(((或 Class.getConstructor((.newInstance((( 创建的对象不是我在该类中实现的接口的实例(以及 Class.getInterfaces(( 返回(。
我定义的加载给定字节码类的方法如下:
public static Class<?> loadClass(String name, URL url, byte[] code) {
Unsafe u = UnsafeKey.getUnsafe();
java.lang.ClassLoader loader = java.lang.ClassLoader.getSystemClassLoader();
Permissions perms=new Permissions();
perms.add(new RuntimePermission("accessDeclaredMembers"));
ProtectionDomain protection = new ProtectionDomain(new CodeSource(url,(Certificate[])null),perms);
return u.defineClass(name, code, 0, code.length, loader, protection);
}
在我的例子中,字节码是使用此方法直接从.class文件(由我的 jdk 编译(加载的:
public static Class<?> loadClass(String name, File f) throws IOException {
byte[] data = new byte[(int) f.length()];
InputStream i = new FileInputStream(f);
i.read(data);
return loadClass(name, f.toURI().toURL(), data);
}
将加载的数据发送到第一种方法。
我用于测试的类实现了一个名为PixelArtist的接口:
import com.ralitski.art.api.PixelArtist;
public class PixelArtistTest implements PixelArtist {
public PixelArtistTest() {}
@Override
public int getWidth() {
return 100;
}
@Override
public int getHeight() {
return 100;
}
@Override
public int getColor(int x, int y) {
int z = x * y;
return x + (y * 255) + z;
}
}
从文件加载这个类,定义它,并创建一个新实例后,我尝试用这种方法使用它(这个对象是通过调用Class.newInstance((创建的(:
private static Artist getArtist(Object o) {
System.out.println(o);
Class c = o.getClass();
System.out.println(c);
System.out.println(c.getSuperclass());
for(Class c2 : c.getInterfaces()) {
System.out.println(" " + c2);
}
System.out.println(PixelArtist.class.isInstance(o));
if(o instanceof Artist) {
System.out.println(1);
return (Artist)o;
} else if(o instanceof PixelArtist) {
System.out.println(2);
return new PixelArtistFeed((PixelArtist)o);
} else {
System.out.println(3);
return null;
}
}
该代码的输出如下:
PixelArtistTest@1947c6b
class PixelArtistTest
class java.lang.Object
interface com.ralitski.art.api.PixelArtist
false
3
如您所见,类将 PixelArtist 列为接口,但从该类创建的对象不是 PixelArtist 类型的实例。
当我定义类时,我尝试向它添加不同的权限(甚至是AllPermission(,并且我尝试使用Class.getConstructor((.newInstance((实例化对象,但此错误仍然存在。
问题是您正在将类装入到系统类装入器中。这个类加载器没有你的接口,或者有另一个接口副本,它有一个不同的类装入器,很可能是你的类装入器。
我建议您使用默认的类加载器,例如与PixelArtist.class.getClassLoader()
相同的类加载器