The root of the problem is the difference between the Object[] toArray()
and Object[] toArray(Object[])
methods in the java.util.Collection
API.
The first form allocates an array of the right size to hold the members of the collection and then assigns the member references into the array. Because the collection class doesn't know what the type of the members actually is (see note below), the API specifies that the result is an instance of Object[]
; i.e. as if it was allocated using new Object[size]
.
The second form takes an array as a parameter that will (normally) be where the collection member references are stored. Thus, the program determines what the type of the result will be by passing an array of the required type. If the supplied array is big enough to hold the collection elements, the toArray
method will return the supplied array instance. If not, a new array is allocated with the same type as the supplied array instance. (This can done reflectively using Array.newInstance(clazz, size)
where clazz
is the supplied array's component class. Note that the type parameter is not used to do this ... and it cannot be used.)
So what is happening is that Eclipse is not smart enough to know that the real correction to your mistake is to use a different method overload. In order to make this correction, it would need to "know" about the specific semantics of the two forms of the toArray
method. That's a tall order IMO.
The lesson is that Eclipse's suggested corrections are Just Suggestions ... and not guaranteed to be the right fix.
Note: The collection class does not know the appropriate array class to create in the toArray()
case because of type erasure. Information about how the type was instantiated is not available to the class that implements toArray
. But considering that it is generally possible to insert into a Collection<T>
something that is not a T
(by ignoring "unsafe typing" compiler warnings) it is maybe a good thing that the result type is an Object[]
!
This problem predates generic types; the two forms of the method have been present since the introduction of the collections framework in Java 1.2.
EDIT: in a comment @Thilo suggested that this problem would not have arisen if Java had supported generics from the start. My answer to that is that it didn't happen that way, and we cannot say what would have happened if they had. But we can say that with Java generics as they are currently defined it is would be impossible to do this without redesigning the collection APIs.
Specifically, a generic class cannot figure out what actual type has been used as a type parameter for a given instance. Without this information, it cannot know the correct array type to instantiate. In practice, if you want a generic type to create instances of the type parameter or some related type, you have to design the APIs so that the relevant methods have runtime access to the actual parameter type's Class
object. For example, the actual Class object could be supplied as a constructor parameter.