2012-09-06 32 views
2

我想了解Java类加载器如何工作,特别是defineClass(String,byte[],int,int)方法。假设我想加载NonIntrinsicType的类定义。我知道我可以找到NonIntrinsicType的* .class文件,将其内容序列化为名为bytesbyte[],然后调用defineClass(null,bytes,0,bytes.length)如何获得数组类的类定义byte []?

我无法理解是一种奇怪的局面,我怎样才能得到一个byte[]对于像[LNonIntrinsicType类定义 - 换句话说,如果我的应用程序请求的类定义的NonIntrinsicType[]一个实例,我不t有一个与这个类类型相对应的* .class文件。如何获得此类型定义的byte[]

您可能想知道为什么我想这样做。我基本上试图创建一个网络类加载器,它具有在其类路径中具有类定义的“本地”JVM,以及在其类路径中没有上述类定义的“远程”JVM。 “远程”遇到NonIntrinsicType[]的一个实例,并要求从“本地”为该类类型定义,但是我的“本地”JVM找不到NonIntrinsicType[]的类文件,因此它无法将类定义byte[]提供为“远程”。

新增2010年9月7日

有一件事我应该提到...我使用SocketObjectInputStream接收发送的“地方”到“远程”的消息。我在“远程”端创建了ObjectInputStream的自定义扩展名,并覆盖了protected Class<?> resolveClass(ObjectStreamClass)。当传入的消息包含尚未加载的类的实例时,这是“远程”JVM获得的第一个通知。我有另一个用于传递类定义的套接字,因此当第一个套接字接收到一个尚未加载的类的实例时,它会通过第二个套接字从“本地”JVM请求该类的定义。

当我的自定义ObjectInputStream.resolveClass(ObjectStreamClass)通过ObjectStreamClass,返回数组类型的名称(该名称看起来像[Lsome.ClassName;)时,会发生此问题。我可以轻松地解析出基本级别some.ClassName并首先加载它 - 这是在NetworkClassLoader.getInstance.loadClass()的调用中完成的,其中我获得基本级别的byte[],然后在该方法调用中使用它调用defineClass()

我现在明白,对于数组类型的类定义,您可能无法获得byte[],因此我试图找出如何为数组类型找到Class<?>实例并将其返回。下面是我的resolveClass方法的代码在我的自定义ObjectInputStream上的“远程” JVM的消息接收Socket

@Override 
protected Class<?> resolveClass(ObjectStreamClass osc) 
     throws IOException, ClassNotFoundException{ 
    try { 
     return super.resolveClass(osc); 
    } catch (Exception e){} 

    String name = osc.getName(); 
    boolean array = name.contains("[L"); 

    if(array) name = name.replace("[L",""). 
      replace("[","").replace(";",""); 

    Class<?> c = NetworkClassLoader.getInstance().loadClass(name); 
    if(!array) return c; 

    //If it's an array type, how do I obtain its corresponding 
    //Class<?> and return it here? 

    throw new ClassNotFoundException(); 
} 
+0

数组可能没有定义它们的字节码。如果您的远程JVM具有元素类型的字节码,是不是可以从那里算出来? – Thilo

回答

3

您不需要为[LType创建定义。如果你有一个Class,你可以用反射创建该类的一个array

Object array = Array.newInstance(yourClass, dimensions); 
+0

哦,当然 - 我知道我不需要为数组类型显式创建类定义,但是这样的定义必须存在某处 - 大概是内存驻留...对吧? http://stackoverflow.com/questions/2009210/in-java-why-are-arrays-objects-are-there-any-specific-reasons – CodeBlind

+0

Duh ...我现在明白了。这工作完美。我的类加载器基本上调用你提到的方法并返回'array.getClass()'。没有更多的问题:)谢谢! – CodeBlind

2

你不用管阵列的负载,因为他们没有加载。没有什么要加载的。没有一个数组的类。没有类定义。没有字节[]。

+3

一个类加载器不会被要求加载'[LSomething'(只是东西)。 (我的假设,有人请确认) – Thilo

+0

这就是我想表达的。 – bmargulies

+0

我明白了。因此,即使“Remote”JVM看到的第一个类名是'[LNonIntrinsicType',我应该让“Local”JVM将NonIntrinsicType定义为“Remote”,然后让“Remote”尝试加载' [LNonIntrinsicType'再次? – CodeBlind

0

可以做到这一点的唯一方法是修补您的JVM的defineClass(...)方法来查找所需的类,然后将它们存储起来以备后用。

0

这摘自ClassLoader的Javadoc:不是由类加载器创建的数组类

类对象,但是 由Java运行时创建自动必需的。对于数组类,由Class.getClassLoader()返回的类加载器 与其加载器的元素类型相同,为 ;如果元素类型 是基本类型,那么该数组类没有类加载器。

理解您的类加载器如何被要求为[LNonIntrinsicType创建类是很有趣的。感觉就像你在做一些自定义的事情。如果你能更详细地描述你在做什么,我们可以更好地理解你的问题。当你的类加载器被要求定义[LNonIntrinsicType时,什么是调用堆栈?