繁体   English   中英

如何避免Java Generics扩展Comparable接口中未经检查的强制转换?

[英]How to avoid unchecked casts in a Java Generics extended Comparable interface?

为什么这个通用接口需要不安全的强制转换(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;
    }
}

因为无法保证this实际上是T类的实例,甚至无法扩展它。

例如,考虑一下:

public class T0 implements ExtendComparable<T0> {...}
public class T1 implements ExtendComparable<T0> {...}

T0符合条件,因为它符合边界: T0 extends ExtendComparable<T0> ,T0 T0 extends ExtendComparable<T0> T0。 在这种情况下, thisT0一个实例,所以你很好; 演员(T)this (因此(T0)this )是有道理的。

对于T1 ,声明也是正确的,因为绑定应用于T0T1T取代T0 然而, thisT1T1不是超级也不是T0的孩子。 是的,都实现了ExtendedCompatible<T0> ,但是你不能在兄弟姐妹之间进行转换。 例如,Integer和Double扩展Number但是(Integer) new Double(0.0)失败。 所以也没有投(T)翻译成(T0)失败。

您正在做的假设是将T设置为与已声明的类相同,并且当前无法强制使用这些语义。 我希望这将在Java语言的未来版本中的某些时候发生变化,但也许实际上存在Java语言“任务组”无法避免这样做的原因。

有一种方法可以完全避免强制转换,但是当你将ExtendedCompatible作为抽象类而不是接口时更好。

您可以声明一个T类型的final字段,该值将由受保护的构造函数通过扩展类来设置,而class又必须将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);
     }
  }

你付出的代价是很傻参考自身和传球的添加的代码/ CPU负担的额外内存消耗this对父类的构造。

另一种方法是声明一个抽象方法来获取T (this):

// Parent abstract class:
   protected abstract T getThiz();
// Child class... for each class:
   protected MyChildClass getThiz() { return this; }

谢谢。 瓦伦丁是对的。 即使两种类型都实现了相同的接口,这也不会也不应该使它们之间的转换工作。 是的,Java中没有任何机制可以强制传入与正在声明的类相同的类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM