为什么这个通用接口需要不安全的强制转换(T)
?如果T
与自身相当,即实现ExtendedComparable<super of T>
,这也意味着ExtendedComparable<T>
,那么为什么类型擦除需要将ExtendedComparable<T>
强制转换为T?
/* @param <T> T must be comparable to itself or any of its superclass
* (comparables are consumers, thus acc. to the PECS principle
* = producer-extends,consumer-super we use the bounded wildcard type "super")
*/
public interface ExtendedComparable<T extends ExtendedComparable<? super T>> {
Comparator<? super T> getComparator();
default boolean greaterThen(T toCompare) {
return getComparator().compare((T) this, toCompare) > 0;
}
}
答案 0 :(得分:5)
因为无法保证this
实际上是类T
的实例,甚至无法扩展它。
例如,考虑一下:
public class T0 implements ExtendComparable<T0> {...}
public class T1 implements ExtendComparable<T0> {...}
在T0
中符合罚款,因为它符合界限:T0 extends ExtendComparable<T0>
并且T0是T0的超级。在这种情况下,this
是T0
的实例,所以你很好;演员(T)this
(因此(T0)this
)是有道理的。
使用T1
声明也是正确的,因为绑定应用于T0
没有T1
,T
被替换T0
。但this
T1
和T1
不是超级,也不是T0
的孩子。是的,都实现了
ExtendedCompatible<T0>
,但你不能在兄弟姐妹之间施放。例如,Integer和Double扩展Number但(Integer) new Double(0.0)
失败。
转化为(T)
的演员(T0)
也失败了。
您所做的假设是T
将被设置为与已声明的类相同,并且目前无法强制使用这些语义。我希望这将在Java语言的未来版本中的某些时候发生变化,但也许实际上存在Java语言“任务组”无法避免这样做的原因。
有一种方法可以完全避免强制转换,但是当你使ExtendedCompatible
成为抽象类而不是接口时更好。
您可以声明类型T
的最终字段,该值将由受保护的构造函数通过扩展类来设置,而该类又必须将this
作为其值传递:
public abstract class ExtendedCompatible<T extends ExtendedCompatible<? super T>> {
private final T thiz;
protected ExtendedCompatible(final T thiz) {
if (this != thiz) throw new IllegalArgumentException("you must pass yourself");
this.thiz = thiz;
}
...
public class MyExtendedCompatible extends ExtendedCompatible<MyExtendedCompatible> {
public MyExtendedCompatible() {
super(this);
}
}
您支付的价格是对自身进行愚蠢引用的额外内存消耗以及将this
传递给父构造函数所增加的代码/ CPU负担。
另一种方法是声明一个抽象方法来获取T
(this):
// Parent abstract class:
protected abstract T getThiz();
// Child class... for each class:
protected MyChildClass getThiz() { return this; }
答案 1 :(得分:0)
感谢。瓦伦丁是对的。即使两种类型都实现了相同的接口,这也不会也不应该使它们之间的转换工作。是的,Java中没有任何机制可以强制传入与正在声明的类相同的类。