java - 使用 Java 的 Unsafe 实现动态类中的接口(interface)

标签 java interface

我正在尝试使用Java的sun.misc.Unsafe.defineClass(String name, byte[] code, int off, int len, ClassLoader classLoader, ProtectionDomain ProtectionDomain)动态加载类,但由于某种原因我创建的对象通过调用 Class.newInstance() (或 Class.getConstructor().newInstance())不是我在该类中实现的接口(interface)的实例(以及 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 的接口(interface):

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 列为接口(interface),但从该类创建的对象不是 PixelArtist 类型的实例。

我尝试在定义类时向该类添加不同的权限(甚至是 AllPermission),并且尝试使用 Class.getConstructor().newInstance() 实例化该对象,但此错误仍然存​​在。

最佳答案

问题是您正在将类加载到系统类加载器中。该类加载器没有您的接口(interface),或者具有该接口(interface)的另一个副本,该副本具有不同的类加载器,很可能是您的类加载器。

我建议您使用默认的类加载器,例如与 PixelArtist.class.getClassLoader()

相同

关于java - 使用 Java 的 Unsafe 实现动态类中的接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27462043/

相关文章:

interface - 避免 swig 中出现 'nothing known about [parent] class...' 错误

java - 如何排除 Maven <reporting> 插件中的依赖项?

java - weblogic从10.3.0升级到10.3.6.0.11后时区格式差异

python - 如何获得实现接口(interface)的类列表? (zope.interface)

java - 如何对没有实现 Iterable 的类使用 for-each 循环

interface - 为什么我想要一个没有端点的 USB 备用接口(interface)?

java - 我可以将 xml 有效负载作为字符串发送到soap web 服务吗

java - 使用lombok时设置log4j级别

java - 使用 Graph API 从 azure AD 获取用户属性

java - Android MVP - 调用服务器