简体   繁体   中英

Why is heap.toArray(new int[0][0]) allowed?

I saw a code like this:

public int[][] test() {
       Queue<Integer> queue = new PriorityQueue<>();
       //Do Something 
       return queue.toArray(new int[0][0])
}

I'm curious about the last line, why is int[0][0] allowed here? Shouldn't the argument to the queue.toArray method be the memory that Array restored into?

The documentation of toArray is here: https://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html#toArray(T[])

toArray 's signature is <T> T[] toArray(T[] a) . So the compiler infers T = int[] . Note that the collection's type parameter is E , not T .

Whatever this code intended to do, most likely it fails, since documentation says:

Throws: ArrayStoreException - if the runtime type of the specified array is not a supertype of the runtime type of every element in this collection

And int[] is not a supertype of Integer .

Shouldn't the argument to the queue.toArray method be the memory that Array restored into?

Not necessarily.

What happens is that the toArray method works out what size array is needed to hold the collection contents. If the supplied array is large enough, then that is where the contents are written. Otherwise a new array is allocated and used. In the latter case, the argument array's actual type determines the type of array that is allocated.


As @ReputationFarmer notes, in this case queue.toArray(new int[0][0]) will probably give a runtime exception ( ArrayStoreException ). The call should be queue.toArray(new Integer[0]) .

The reason that this doesn't give a compilation error is that the type signature of this toArray method is <T> T[] toArray(T[] a) which allows any array type to be passed as an argument.


So ... why did they define toArray that way?

The answer is in the history of Java:

  • The toArray methods are specified in the Collection API which was added to Java in Java 1.2.

  • From Java 1.2 to Java 1.4.2, the signature for this method was:

     public Object[] toArray(Object[] a) 

    In other words, you could pass an array of any reference type, and the compiler would accept it.

  • In Java 5, they introduced generics, and redefined the toArray method to have its current signature.

I suspect that the reason that they didn't redefine the toArray signature to be:

    <T extends E> T[] toArray(T[] a)

is that it would break (give compilation errors) for some Java code that was valid with earlier releases.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM