为什么Object[].class.isAssignableFrom(String[].class) == true? 为什么Object[].class可以赋值给String[].class?

3
为什么在Java中 Object[].class.isAssignableFrom(String[].class) == true,而 String[].getSuperClass() 或者 getGenericInterfaces() 却不能获取 Object[]
我查看了JDK的源代码,但是并不确定自己能否找到答案。现在,我知道JDK使用树来存储类之间的关系,并使用深度来指示其级别,Class::isAssignableFrom() 搜索该链,所以数组肯定在这个树里面。同时,也可以看出 String[]Object[] 相连。
那么,我能否说 String[]Object[] 的子类呢? 或者这只是Java的另一个奇怪的事情?
4个回答

6

Class.isAssignableFrom()主要检查子类型关系。 "subtype"和"subclass"是两个不同的概念。类层次结构(即子类)只是子类型的一部分。

原始类型数组类型有特殊的子类型情况。

数组类型的子类型规则如下(注意,“> 1 ”表示“是直接子类型”):

  • 如果S和T都是引用类型,则S [] > 1 T []当且仅当S > 1 T。
  • Object > 1 Object []
  • Cloneable > 1 Object []
  • java.io.Serializable > 1 Object []
  • 如果p是原始类型,则:
    • Object > 1 p []
    • Cloneable > 1 p []
    • java.io.Serializable > 1 p []

对于您的问题,重要的部分是第一项:如果组件类型X是组件类型Y的子类型,则数组类型X []是数组类型Y []的子类型。

另外需要注意的是,严格来说,Object[]String[]都不是类,它们只是“类型”。虽然每个类都隐式地是一种类型,但反过来则不成立。另一个不是类而是类型的例子是原始类型:booleanbytecharshortintlongfloatdouble都是类型,但它们不是类。
造成混淆的另一个原因是您可以轻松获得表示这些类型java.lang.Class对象。再次强调:这并不意味着这些类型是类。

哇,你从哪里得到这些规则的?能给我一个链接吗?看起来 String[] 是 Object[] 的子类。非常感谢。 - Brodie
1
不,String[]并不是Object[]的子类!这就是我一直在说的!它是一个子类型,但那是另一回事!顺便说一下,我一直在我的答案中提供规则链接。 - Joachim Sauer

2
在Java(和.NET)中,数组是协变的。这意味着如果Apple继承自Fruit,则可以将Apple[]类型的实例传递给期望Fruit[]的方法。以下代码是有效的:
Fruit[] fruits = apples; // apples is an Apple[]

这意味着一个Fruit[]可以被赋值为Apple[]
当然,这并不是很安全。假设:
void someMethod(Object[] objects) {
    objects[0] = "Hello World"; // throws at run time.
}

void test() {
    Integer[] integers = new Integer[10];
    integers[0] = 42;
    someMethod(integers); // compiles fine.
}

这个设计决策在你想使用数组内容(如打印)但不修改它时非常方便。

你展示的代码将会在运行时抛出 ArrayStoreException 异常! - Joachim Sauer
根据基本类型的对象进行修改或修改,这就是多态的目的。 - Nerdfest

0

因为 String[] 实际上可以转换/扩展为 Object[]

你可能会认为这个测试是检查 String[] 是否可以从 Object[] 赋值,但实际上 它测试的是相反的情况(即 String[] 是否可以被赋值给 Object[])。

这段代码编译并按预期执行:

public static void main(String[] args) {
    String[] strings = new String[]{ "hello", "world" };
    printArray(strings);
}

public static void printArray(Object[] array) {
    for (Object obj : array) {
        System.out.println(obj);
    }
}

0
如果这个对象表示一个数组类,则返回代表Object类的Class对象。link

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接