跨类加载器?

Itt*_*ayD 25 java classloader

我怎样才能做到这一点:

class Foo {
  public static Foo get() throws Exception {
    ClassLoader cl = new URLClassLoader(new URL[]{"foo.jar"}, null); // Foo.class is in foo.jar
    return (Foo)cl.loadClass("Foo").newInstance(); // fails on class cast
  }
}
Run Code Online (Sandbox Code Playgroud)

我需要的是让JVM从cl中考虑Foo实例,就好像它是来自执行代码的类加载器的Foo实例一样.

我见过这些方法,对我来说都没有好处(上面的例子是玩具示例):

  1. 通过类加载器加载类(或单独的接口),类加载器是调用代码和创建的类加载器的父级
  2. 序列化和反序列化对象.

Mic*_*rdt 27

不可能.类标识由完全限定名称和类加载器组成.

将对象转换为具有由不同类加载器加载的相同名称的类与尝试转换为Stringto 没有什么不同Integer,因为尽管具有相同的名称,这些类实际上可能完全不同.

  • 那么,如果我们连这些新实例都无法投射,我们该如何利用它们呢?如果我们能做的就是 `Object obj = cl.loadClass("Foo").newInstance();`,那么我们如何调用新的 Foo 实例的方法呢? (2认同)
  • @Pacerier:好吧,你可以使用反射。但更实际的情况是让类扩展类或实现来自委托层次结构中的父类加载器的接口,这些接口也可供其余代码使用。但在示例代码中,没有父类加载器(构造函数的第二个参数为空)... (2认同)

小智 8

我刚刚花了两天时间来解决这个问题,我终于通过使用java反射解决了这个问题:

// 'source' is from another classloader
final Object source = events[0].getSource();

if (source.getClass().getName().equals("org.eclipse.wst.jsdt.debug.internal.core.model.JavaScriptThread")) {

    // I cannot cast to 'org.eclipse.wst.jsdt.debug.internal.core.model.JavaScriptThread'
    // so I invoke the method 'terminate()' manually
    Method method = source.getClass().getMethod("terminate", new Class[] {});
    method.invoke(source, new Object[] {});
}
Run Code Online (Sandbox Code Playgroud)

希望这有助于某人.

  • 如果没有反思,我们怎么做呢?如果我们的类加载器加载的每个单个对象的每个方法都需要通过反射来调用,那么这不会严重影响整个程序吗? (2认同)

小智 8

如果需要强制转换的类实现Serializable,那么:

private <T> T castObj(Object o) throws IOException, ClassNotFoundException {
    if (o != null) {
        ByteArrayOutputStream baous = new ByteArrayOutputStream();
        {
            ObjectOutputStream oos = new ObjectOutputStream(baous);
            try {
                oos.writeObject(o);
            } finally {
                try {
                    oos.close();
                } catch (Exception e) {
                }
            }
        }

        byte[] bb = baous.toByteArray();
        if (bb != null && bb.length > 0) {
            ByteArrayInputStream bais = new ByteArrayInputStream(bb);
            ObjectInputStream ois = new ObjectInputStream(bais);
            T res = (T) ois.readObject();
            return res;
        }
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

用法:

Object o1; // MyObj from different class loader
MyObj o2 = castObj(o1);
Run Code Online (Sandbox Code Playgroud)


sgr*_*lon 7

不可能在不同的类加载器中进行转换。

您可以使用 Gson 来解决此问题,例如将 Object 转换为 YourObject(Object 是 YourObject 类,但在其他类加载器中):

Object o = ... 
Gson gson = new Gson();
YourObject yo = gson.fromJson(gson.toJson(o), YourObject.class);
Run Code Online (Sandbox Code Playgroud)

我使用此解决方法是因为我在 WebApp(在 Tomcat 上)中编译任何 Java 代码。此解决方法在生产中运行。