我想了解Java类加载器如何工作,特别是defineClass(String,byte[],int,int)
方法。假设我想加载NonIntrinsicType
的类定义。我知道我可以找到NonIntrinsicType
的* .class文件,将其内容序列化为名为bytes
的byte[]
,然后调用defineClass(null,bytes,0,bytes.length)
。如何获得数组类的类定义byte []?
我无法理解是一种奇怪的局面,我怎样才能得到一个byte[]
对于像[LNonIntrinsicType
类定义 - 换句话说,如果我的应用程序请求的类定义的NonIntrinsicType[]
一个实例,我不t有一个与这个类类型相对应的* .class文件。如何获得此类型定义的byte[]
?
您可能想知道为什么我想这样做。我基本上试图创建一个网络类加载器,它具有在其类路径中具有类定义的“本地”JVM,以及在其类路径中没有上述类定义的“远程”JVM。 “远程”遇到NonIntrinsicType[]
的一个实例,并要求从“本地”为该类类型定义,但是我的“本地”JVM找不到NonIntrinsicType[]
的类文件,因此它无法将类定义byte[]
提供为“远程”。
新增2010年9月7日
有一件事我应该提到...我使用Socket
和ObjectInputStream
接收发送的“地方”到“远程”的消息。我在“远程”端创建了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();
}
数组可能没有定义它们的字节码。如果您的远程JVM具有元素类型的字节码,是不是可以从那里算出来? – Thilo