Why Object[].class.isAssignableFrom(String[].class) == true?
Why is Object[].class.isAssignableFrom(String[].class) == true
, while String[].getSuperClass()
or getGenericInterfaces()
could开发者_JS百科 not get Object[]
?
I checked the source of JDK, but i don't think i can get the answer myself.
For now, I know JDK uses tree to store the relationship between Classes, and depth to indicate its level, Class::isAssignableFrom()
searched the chain, so definately arrays are in that tree. and also String[]
is connected to Object[]
.
Can i say that String[]
is a subclass of Object[]
?
Or is it just another weird thing of Java?
Class.isAssignableFrom()
essentially checks the subtyping relation. "subtype" and "subclass" are two different concepts. The class hierarchy (i.e. subclassing) is only a part of subtyping.
Primitive types and array types have special cases for subtyping.
The rules for subtyping of array types are like this (note that ">1" means "is a directy subtype of"):
- If
S
andT
are both reference types, thenS[]
>1T[]
iffS
>1T
.Object
>1Object[]
Cloneable
>1Object[]
java.io.Serializable
>1Object[]
- If
p
is a primitive type, then:
Object
>1p[]
Cloneable
>1p[]
java.io.Serializable
>1p[]
The important part for your question is the very first item: an array type X[]
is a subtype of an array type Y[]
if and only if the component type X
is a subtype of the component type Y
.
Also note that strictly speaking neither Object[]
nor String[]
are classes. They are "only" types. While every class implicitly is a type, the reverse is not true. Another example of types that are not classes are the primitive types: boolean
, byte
, char
, short
, int
, long
, float
and double
are types, but they are not classes.
Another cause for confusion is the fact that you can easily get java.lang.Class
objects representing those types. Again: This does not mean that those types are classes.
In Java (and .NET), arrays are covariant. It means you can pass an instance of type Apple[]
to a method that expects a Fruit[]
if Apple
inherits Fruit
. The following line is valid:
Fruit[] fruits = apples; // apples is an Apple[]
This means a Fruit[]
is assignable from Apple[]
.
This is not very safe, of course. Assume:
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.
}
This design decision is handy when you want to use arrays contents (e.g. print it) but not modify it.
Because String[]
can actually be converted/widened to Object[]
.
You might be thinking that this tests if String[]
is assignable from Object[]
, but it actually tests the reverse (if String[]
can be assigned to Object[]
).
This code compiles and executes as expected:
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);
}
}
If this object represents an array class then the Class object representing the Object class is returned.link
精彩评论