ClassLoader可以用任何东西替换数组

时间:2016-12-13 02:26:46

标签: java jvm classloader

当我运行以下Java代码时:

ClassLoader c = new ClassLoader() {
    @Override
    public Class<?> findClass(String name) {
        return Object.class;
    }
};

Class<?> cc = c.loadClass(Object[][].class.getName());

System.out.println(cc.getName());

即使我在代码中将java.lang.Object替换为Object[][].class.getName(),我也会在显示终端中获得[[Ljava.lang.Object。问题是我希望控制台显示[[Ljava.lang.Object

实际上,在JVM specification中,我可以阅读以下内容:

  

数组类由Java虚拟机(第5.3.3节)直接创建,而不是由类加载器创建。但是,D的定义类加载器用于创建数组类C的过程。

由于Object[][]是一个数组类,我假设我的findClass不会使用参数[[Ljava.lang.Object调用,而是使用其元素类型java.lang.Object

此外,在“创建数组类”一节中,实际描述了递归算法:

  

如果组件类型是引用类型,则使用类加载器L递归应用本节(第5.3节)的算法以加载,从而创建C的组件类型。

所以我的问题是:

  • 为什么我得到这个输出?这是否意味着我必须在我的ClassLoader中手动包含这个递归算法,而不是让JVM为我做这个?如果这意味着什么,最好的方法是什么?
  • 我是否误解了第一个引文中的“已创建”?它是否只是意味着我无法创建运行时数组类,但我仍然可以修补它的加载?

1 个答案:

答案 0 :(得分:4)

您正在询问JVM规范,但您的测试演示了POST /query的行为,java.lang.ClassLoader是一个独立的类"invoked by the Java virtual machine to resolve class references"。如果JVM正在加载数组类,它将完全绕过类加载器。这可以通过让JVM尝试使用自定义类加载器加载类来证明:

Class<?> clazz = Class.forName("[[Lcom.foo.Test;", true, new ClassLoader() {
    @Override
    public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        System.out.println("Loading " + name);
        return super.loadClass(name, resolve);
    }
});
System.out.println(clazz);

输出:

Loading com.foo.Test
class [[Lcom.foo.Test;

如您所见,组件类型最初是通过类加载器加载的,但是数组类型是隐式加载的。