为什么Object[].class.isAssignableFrom(String[].class) == true
,而String[].getSuperClass()
或getGenericInterfaces()
无法获得Object[]
?
我检查了JDK的来源,但我认为我自己无法得到答案。
现在,我知道JDK使用树来存储Classes之间的关系,并使用深度来指示它的级别,Class::isAssignableFrom()
搜索链,所以绝对数组在那个树中。并且String[]
也与Object[]
相关联。
我可以说String[]
是Object[]
的子类吗?
或者它只是Java的另一个奇怪的东西?
答案 0 :(得分:6)
Class.isAssignableFrom()
基本上会检查subtyping relation。 “subtype”和“subclass”是两个不同的概念。类层次结构(即子类化)只是子类型的一部分。
Primitive types和array types有特殊情况需要进行子类型分析。
数组类型的子类型规则是这样的(请注意,“> 1 ”表示“是一个直接的子类型”):
- 如果
S
和T
都是参考类型,那么S[]
> 1T[]
iffS
&gt; < sub> 1T
。Object
&gt; 1Object[]
Cloneable
&gt; 1Object[]
java.io.Serializable
&gt; 1Object[]
- 如果
p
是基本类型,则:
Object
&gt; 1p[]
Cloneable
&gt; 1p[]
java.io.Serializable
&gt; 1p[]
您的问题的重要部分是第一项:当且仅当组件类型X[]
是子类型时,数组类型Y[]
是数组类型X
的子类型组件类型Y
。
另请注意,严格来说,Object[]
和String[]
都不是类。它们是“唯一”类型。虽然每个类隐式都是一个类型,但事实并非如此。非类型的另一个示例是基本类型:boolean
,byte
,char
,short
,int
,long
,{ {1}}和float
是类型,但它们不是类。
造成混淆的另一个原因是您可以轻松获取代表类型的double
个对象。再说一遍: not 意味着那些类型是类。
答案 1 :(得分: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.
}
当您想要使用数组内容(例如打印它)但不修改它时,此设计决策很方便。
答案 2 :(得分:0)
因为String[]
实际上可以转换/扩展为Object[]
。
您可能会认为此测试是String[]
可以从Object[]
分配,but it actually测试相反(如果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);
}
}
答案 3 :(得分:0)
如果此对象表示数组类,则返回表示Object类的Class对象。link