我不明白为什么当参数化类型被定义为扩展基类时,编译器无法看到强制转换是安全的。以下是演员的例子,在我看来他们应该是不必要的。此外,当我确实包含演员表时,我的IDE(IntelliJ IDEA)会警告演员表未经检查,好像是表明我做错了。有没有避免这些演员和警告的成语?为什么需要强制转换,因为声明声明类型扩展了基类?
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;
}
}
答案 0 :(得分:5)
T延伸形状,多边形延伸形状。 所以T没有理由扩展Polygon
答案 1 :(得分:5)
我们假设你已经像这样实例化了你的类:
Foo<Circle> circleFoo = new Foo<Circle>( );
然后,Set<Circle>
无法安全地分配HashSet<Polygon>
在getFirst
中:您无法安全地将Polygon
投射到Circle
在getShapes
中:您无法安全地将Iterable<Polygon>
投射到Iterable<Circle>
。
答案 2 :(得分:1)
答案 3 :(得分:1)
Set<T> shapes = (Set<T>) new HashSet<Polygon>();
需要强制转换为T
此处可以是任何扩展Shape
并且您尝试仅适合多边形的内容。 Circle
是shape
,但不是Polygon
。最佳实践是将参数化泛型视为唯一类。
如果java在没有强制转换的情况下允许上述内容,则会打开一扇门,将T
添加到set
。想象一下,您已将Polygon
集分配给Set<T>
,然后向其添加了Circle
个对象。这引发了许多运行时问题。
答案 4 :(得分:1)
// Why must this be cast?
Set<T> shapes = (Set<T>) new HashSet<Polygon>();
这是你遇到的最少的问题。转换实际上逻辑上不正确。如果A和B不同,Set<A>
不是Set<B>
的子类型,即使A是B的子类型。如果我们有可再生的泛型,那么这个演员会失败。
答案 5 :(得分:0)
在第一个示例中,Set<T>
不是HashSet<Polygon>
的基类。
在第二个示例中,polygons.iterator().next()
的类型为Polygon
,与T
不同。