Reputation: 2147
I do not understand why the compiler can not see that a cast is safe when the parameterized type is defined as extending a base class. Here are examples of casts that seem to me like they should be unnecessary. Further, when I do include the cast, my IDE (IntelliJ IDEA) warns that the cast is unchecked, as if to suggest that I am doing something wrong. Is there an idiom that avoids these casts and warnings? Why are the casts needed at all, given that the declaration states that the type extends the base class?
class Shape {}
class Polygon extends Shape {}
public class Foo<T extends Shape>
{
Set<Polygon> polygons;
// Why must this be cast?
Set<T> shapes = (Set<T>) new HashSet<Polygon>();
T getFirst()
{
// Why must this be cast?
return (T) polygons.iterator().next();
}
Iterable<T> getShapes()
{
// Why must this be cast?
return (Iterable<T>) polygons;
}
}
Upvotes: 2
Views: 1216
Reputation: 122439
// Why must this be cast?
Set<T> shapes = (Set<T>) new HashSet<Polygon>();
This is the least of your problems. The conversion is actually logically incorrect. Set<A>
is not a subtype of Set<B>
if A and B are different, even if A is a subtype of B. If we had reifiable generics this cast would fail.
Upvotes: 1
Reputation: 3163
Set<T> shapes = (Set<T>) new HashSet<Polygon>();
A cast is needed as T
here can be anything that extends Shape
and you are trying to fit only Polygons. Circle
is a shape
but its not Polygon
. The best practice is to treat parameterized generics as a unique class.
If java allowed the above without the cast, it would then be opening a door for adding any T
to the set
. Imagine you assigned your Polygon
set to a Set<T>
and then added Circle
objects to it. That's inviting lots of runtime problems.
Upvotes: 1
Reputation: 49085
You may be interested in reading this about Java generics.
Basically,
Box<Integer> and Box<Double> are not subtypes of Box<Number>
Upvotes: 1
Reputation: 45576
Let's assume you've instantiated your class like this:
Foo<Circle> circleFoo = new Foo<Circle>( );
Then, Set<Circle>
cannot be safely assigned HashSet<Polygon>
In getFirst
: You cannot safely cast Polygon
to Circle
And in getShapes
: you cannot safely cast Iterable<Polygon>
to Iterable<Circle>
.
Upvotes: 5
Reputation: 2218
T extends Shape, Polygon extends Shape. So there is no reason that T extends Polygon
Upvotes: 5
Reputation: 272487
In the first example, Set<T>
is not a base class of HashSet<Polygon>
.
In the second example, the type of polygons.iterator().next()
is Polygon
, which is not the same as T
.
Upvotes: 0