簡體   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