tags:

views:

177

answers:

4

Why is Object[].class.isAssignableFrom(String[].class) == true, while String[].getSuperClass() or getGenericInterfaces() could 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?

+2  A: 

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.

Mehrdad Afshari
The code you showed will throw an `ArrayStoreException` at runtime!
Joachim Sauer
... or modify it based on objects of the base type, the purpose of polymorphism.
Nerdfest
A: 

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);
 }
}
matt b
A: 

If this object represents an array class then the Class object representing the Object class is returned.link

prateek urmaliya
You linked to the wrong method.
matt b
+3  A: 

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 and T are both reference types, then S[] >1 T[] iff S >1 T.
  • Object >1 Object[]
  • Cloneable >1 Object[]
  • java.io.Serializable >1 Object[]
  • If p is a primitive type, then:
    • Object >1 p[]
    • Cloneable >1 p[]
    • java.io.Serializable >1 p[]

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.

Joachim Sauer
wow, where did you get the rules? can you give me a link? it seems String[] is subclass of Object[]. thank you a lot
Brodie
No, String[] +is not a subclass+ of Object[]! That's what I'm saying all the time! It's a +subtype+, but that's a dfferent thing! I've had the links to the rules in my answer all the time, btw.
Joachim Sauer