2015-09-25 133 views
10

如何創建一個泛型類來引用嵌套的泛型類型?如何在Java中使用泛型來引用嵌套類型?

我想創建一個Comparator類,它可以比較B的內部類型而不想公開這些類型是什麼。在下面的例子中,我得到粗鑄件我的T內部嵌套值的編譯器警告可比:

public class SSCCE { 

    // Compare my A instances. 
    class AComparator<T extends B> implements Comparator<T> { 

     @Override 
     public int compare(final T o1, final T o2) { 
      return o1.getValue().compareTo(o2.getValue()); 
     } 
    } 


    class A extends B<Integer> { 
     @Override Integer getValue() { return 1; } 
    } 

    class A2 extends B<String> { 
     @Override String getValue() { return "Test String!"; } 
    } 

    abstract class B<T extends Comparable<T>> { 
     abstract T getValue(); 
    } 

    public static void main(String[] args) { 
     SSCCE sscce = new SSCCE(); 
     AComparator<A> comparator = sscce.new AComparator<>(); 
     comparator.compare(sscce.new A(), sscce.new A()); 
    } 
} 

是否有可能使用到放心地讓鑄造代表內在價值?

事情我已經嘗試:

  • 創建一個通配符可比性(不可編譯):

    class AComparator2<T extends B<? extends Comparable<?>>> implements Comparator<T> { 
    
        @Override 
        public int compare(final T o1, final T o2) { 
         Comparable<?> o1value = (Comparable) o1.getValue(); 
         Comparable<?> o2value = (Comparable) o2.getValue(); 
         return o1value.compareTo(o2value); 
        } 
    } 
    
  • 聲明二級泛型參數類型(U),它只是推遲問題:

    class AComparator3<T extends B<U>, U extends Comparable<U>> implements Comparator<T> { 
    
        @Override 
        public int compare(final T o1, final T o2) { 
         U o1value = o1.getValue(); 
         U o2value = o2.getValue(); 
         return o1value.compareTo(o2value); 
        } 
    } 
    ... 
    AComparator3<A, Comparable<U>> comparator = sscce.new AComparator3(); 
    

這個比較器不是比較類A的兩個實例,而是比較它們的部分內容。

+0

'AComparator3 比較= sscce.new AComparator3 ();'工作正常,你的第二個解決方案 – user902383

+0

它做,但_if possible_我不想靠暴露內部類型。我不指望開發者知道他們是什麼。 – Creperum

回答

7

通配符解決方案不起作用

class AComparator2<T extends B<?>> { 
     public int compare(T o1, T o2) 

因爲T太鬆在這裏;我們不能確定兩個T可以相互比較 - 有可能o1B<X1>o2B<X2>X1, X2是兩種不同的類型。

你的第三個解決方案限制T到特定B<U>

class AComparator3<T extends B<U>, U extends Comparable<U>> 

這個完美的作品;除了使用場所必須指定U,即使U可從T中扣除。

AComparator3<A, Integer> 
        ^^^^^^^ duh! 

這很煩人。其他用例之前也有同樣的問題。沒有好的答案。

幸運的是,你的情況,是不是需要在任何地方使用上現場U,所以我們可以簡單地使用通配符它

AComparator3<A, ?> comparator = sscce.new AComparator3<>(); 
    comparator.compare(sscce.new A(), sscce.new A()); 

事實上,比較是Comparator<A>,這可能是你需要。此外,我們可以創建一個方便的方法來掩蓋new的醜陋。所以,你可以做這樣的事情

Comparator<A> comparator = sscce.comparator(); 
+0

好的答案。一旦我有機會測試它,我會接受它。 – Creperum

+0

上面的代碼給出了線編譯錯誤: 'AComparator3 比較= sscce.new AComparator3 <>();' 和 '比較比較器2 = sscce.new AComparator3 <>();' 錯誤是:'不能推斷AComparator3的類型參數<>' 您遇到過類似的問題嗎? – Creperum

1

有幾件事情你必須改變,以實現你想要的,我相信如果只是實現一個通用的Comparator

首先,AComparator應該是這樣的:

// Compare my A instances. 
class AComparator<T extends Comparable<T>> implements Comparator<T> { 

    @Override 
    public int compare(final T o1, final T o2) { 
     return o1.compareTo(o2); 
    } 
} 

你不需要類B,因爲A和A2將直接實現Comparable。只要刪除它。

你的A和A2類:

class A implements Comparable<A> { 
    @Override public int compareTo(A other) { 
     // your compare logic here 
     // return negative if less than, 0 if equal, positive if greater than 
    } 
} 

class A2 implements Comparable<A2> { 
    @Override public int compareTo(A2 other) { 
     // your compare logic here 
     // return negative if less than, 0 if equal, positive if greater than 
    } 
} 

您閱讀文檔Comparable,瞭解什麼是從返回的值預期是很重要的。

這有道理嗎?

PS:我沒有測試這些代碼,它們剛剛出現在我的腦海中。

+0

抱歉,我沒有在問題中說清楚:我比較了這些實例的內容。 – Creperum

3

你認爲Java 8的解決方案嗎?

Comparator<A> comparator = ((t1,t2)-> t1.getValue().compareTo(t1.getValue())); 
    comparator.compare(sscce.new A(), sscce.new A()); 
+1

鎖定到JDK 7(不幸!) – Creperum

+0

說比較器> c1 =比較器會更有意義。比較(B :: getValue);'目標是創建一個比較器,它不*暴露'A'(儘管它能夠比較'A's)。 – Holger

+1

@Holger我相信OP不想暴露內部類型不是A – user902383

1

另一種選擇是讓B實現Comparable,因爲您使用getValue()來執行比較。下面擺脫了警告:

import java.util.Comparator; 

public class SSCCE { 
    class A extends B<Integer> { 
     @Override Integer getValue() { return 1; } 
    } 

    class A2 extends B<String> { 
     @Override String getValue() { return "Test String!"; } 
    } 

    abstract class B<T extends Comparable<T>> implements Comparable<B<T>>{ 
     abstract T getValue(); 

     @Override 
     public int compareTo(B<T> other) 
     { 
     return getValue().compareTo(other.getValue()); 
     } 
    } 

    public static void main(String[] args) { 
     SSCCE sscce = new SSCCE(); 
     Comparator.naturalOrder().compare(sscce.new A(), sscce.new A()); 
    } 
} 
1

我想這是你想要什麼:

public class SSCCE { 

    static class BComparator<E extends Comparable<E>> implements Comparator<B<E>> { 

     @Override 
     public int compare(final B<E> o1, final B<E> o2) { 
      return o1.getValue().compareTo(o2.getValue()); 
     } 
    } 

    static class A extends B<Integer> { 
     @Override Integer getValue() { return 1; } 
    } 

    static class A2 extends B<String> { 
     @Override String getValue() { return "Test String!"; } 
    } 

    static abstract class B<T extends Comparable<T>> { 
     abstract T getValue(); 
    } 

    public static void main(String[] args) { 
     SSCCE sscce = new SSCCE(); 
     BComparator<Integer> comparator = new BComparator<>(); 
     comparator.compare(new A(), new A()); 

     BComparator<String> comparator2 = new BComparator<>(); 
     comparator2.compare(new A2(), new A2()); 
    } 
} 

如果你不想讓你比較能夠比較B的兩個不同的子類的實例(如A2 extends B<String>A3 extends B<String>),以下工作:

public class SSCCE { 

    static class BComparator<E extends Comparable<E>, T extends B<E>> implements Comparator<T> { 

     @Override 
     public int compare(final T o1, final T o2) { 
      return o1.getValue().compareTo(o2.getValue()); 
     } 
    } 

    static class A extends B<Integer> { 
     @Override Integer getValue() { return 1; } 
    } 

    static class A2 extends B<String> { 
     @Override String getValue() { return "Test String!"; } 
    } 

    static abstract class B<T extends Comparable<T>> { 
     abstract T getValue(); 
    } 

    public static void main(String[] args) { 
     SSCCE sscce = new SSCCE(); 
     BComparator<Integer, A> comparator = new BComparator<>(); 
     comparator.compare(new A(), new A()); 

     BComparator<String, A2> comparator2 = new BComparator<>(); 
     comparator2.compare(new A2(), new A2()); 
    } 
} 
3

您可能感興趣的比較應該比較類型的擴展B,而只有當他們^ h舊的相同類型。這樣的比較可能看起來像

class AComparator<T extends Comparable<T>> implements Comparator<B<T>> { 
    @Override 
    public int compare(final B<T> o1, final B<T> o2) { 
     return o1.getValue().compareTo(o2.getValue()); 
    } 
} 

,您可以使用它像

AComparator<Integer> comparator = sscce.new AComparator<>(); 
comparator.compare(sscce.new A(), sscce.new A()); 
comparator.compare(sscce.new A(), sscce.new A2());//compilation error