跨类加载器?

时间:2010-04-07 10:57:50

标签: 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
  }
}

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

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

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

6 个答案:

答案 0 :(得分:25)

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

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

答案 1 :(得分: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[] {});
}

希望这有助于某人。

答案 2 :(得分:6)

如果需要强制转换的类实现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;
}

用法:

Object o1; // MyObj from different class loader
MyObj o2 = castObj(o1);

答案 3 :(得分:3)

使用接口和java.lang.reflect.Proxy的东西可能适合您的偏好。使用InvocationHandler查找并调用目标类的相关方法。 (请注意,如果您执行此操作,您将获得的任何移动代码安全性。)

答案 4 :(得分:2)

无法在不同的classLoader中进行投射。

你有这个解决方法与Gson,示例强制转换对象到YourObject(对象是一个YourObject类,但在其他classLoader中):

function nexttrack()
   vlc.playlist.delete(itemId)
   vlc.playlist.next()
   delete()
end

function delete()
   os.remove(filename) -- do nothing at this time
end

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

答案 5 :(得分:0)

这是我到达的一篇旧帖子,因为我想做几乎相同的事情,但是它的一个更简单的版本......

如果Foo和加载的类(在我的情况下来自另一个包中的.java类文件)扩展了同一个类,比如AbstractTestClass,它实际上是有效的。

代码:

public AbstractTestClass load(String toLoad) {
    try{
        Class test = Class.forName("testsFolder.testLoadable");
        Constructor ctorlist[] = test.getDeclaredConstructors();
        for(Constructor aConstructor : ctorlist){
           if(...){// find the good constructor
              Object loadedTest = aConstructor.newInstance(new Object[]{/*params*/});
              return (AbstractTestClass) test;
           }
        }
    }catch(...){}
    return new defaultTestClass();
}

这样我可以将加载的类插入ArrayList<AbstractTestClass>