3

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?

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Brodie
  • 31
  • 1
  • 2

4 Answers4

6

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
  • 302,674
  • 57
  • 556
  • 614
  • 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 Oct 30 '09 at 16:56
  • 1
    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 Oct 30 '09 at 17:03
2

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
  • 414,610
  • 91
  • 852
  • 789
0

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
  • 138,234
  • 66
  • 282
  • 345
0

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

urmalp
  • 382
  • 2
  • 4
  • 20