Why Collection.toArray(T[]) doesn't take an E[] instead

前端 未结 2 1769
说谎
说谎 2021-01-04 12:54

The toArray method (lets pick the implementation in java.util.ArrayList) is the following:

class ArrayList ....{
    public  T         


        
相关标签:
2条回答
  • 2021-01-04 13:46

    The point of the <T> is if the array desired is of a base class of E. For example if E is HashMap but the desired array was Map[]. If toArray were locked down to E this would not be possible.

    This type of thing is not needed in generic collections / types due to type-erasure. But there is no type-erasure with arrays so the type of the array can be very important.

    0 讨论(0)
  • 2021-01-04 13:50

    I think John B's answer covered the idea well - I'd just like to elaborate on it a little.

    First, let's look at the method signature you proposed in your question:

    public E[] toArray(E[] a)
    

    As John explained, this signature is less flexible. If I want to dump an ArrayList<Integer> into a Number[], this method doesn't let me. The Collections API wants to allow that flexibility.

    Unfortunately the method as it stands doesn't allow for compile-time checking on the type of the array, which is the issue you seem to be getting at. The documentation for toArray, which is declared by the Collection, explains that an ArrayStoreException may be thrown "if the runtime type of the specified array is not a supertype of the runtime type of every element in this collection".

    Based on that description, it seems like the following signature would be ideal:

    public <T super E> T[] toArray(T[] a)
    

    At first glance, this seems like it would allow any legal type of array to be passed in and populated - but would provide type checking at compile time instead of run time. So why is this signature not declared instead?

    Well, this syntax:

     <T super E>
    

    is not supported by the language. But it's easy for that to distract you from the fact that this type checking wouldn't work anyway. The problem is that unlike parameterized types, arrays are covariant. An Integer[] is a Number[] is an Object[]. So given our hypothetical signature with <T super E>, if I called toArray on an ArrayList<Number> and passed in an Integer[], it would still compile - and possibly fail at runtime depending on what was in the list.

    So the bottom line is, a lower bound on the component type of the array passed in isn't going to do any good.

    0 讨论(0)
提交回复
热议问题