2010-07-07 194 views
9

我試圖編寫一個具有泛型成員變量但不是泛型的類。具體而言,我想說的是,我有一個「實現與自身相媲美的某種類型」的值列表,以便我可以在該列表上調用排序......我希望這是有道理的。非泛型類中的泛型實例變量

我想要做的最終結果是創建一個類,以便我可以創建一個具有(任何給定類型)數組的類的實例,並讓它爲該列表生成一個字符串表示形式。在實際的代碼,我也通過在課堂上,我傳入類型:

String s = new MyClass(Integer.class, 1,2,3).asString(); 
assertEquals("1 or 2 or 3", s); 
String s = new MyClass(String.class, "c", "b", "a").asString(); 
assertEquals("\"a\" or \"b\" or \"c\"", s); 

本來我根本不想在課堂上通過,我只是想在價值傳遞和有代碼檢查結果數組以挑選值的類......但這也給我帶來麻煩。

以下是我的代碼,但我不能想出正確的魔力把該變量的類型。

public class MyClass { 
    // This doesn't work as T isn't defined 
    final List<T extends Comparable<? super T>> values; 

    public <T extends Comparable<? super T>> MyClass (T... values) { 
     this.values = new ArrayList<T>(); 
     for(T item : values) { 
      this.values.add(item); 
     } 
    } 

    public <T extends Comparable<? super T>> List<T> getSortedLst() { 
     Collections.sort(this.values); 
     return this.values; 
    } 
} 

錯誤的變量聲明行:

Syntax error on token "extends", , expected 

任何幫助將是非常讚賞。

編輯:更新的代碼使用列表而不是數組,因爲我不確定它可以用數組完成。

@馬克:一切從我讀過,我真想說:「T是一個類型,它是相當於自己」,而不是「T是一個類型,它是可比的。」話雖這麼說,下面的代碼無法正常工作或:

public class MyClass { 
    // This doesn't work 
    final List<? extends Comparable> values; 

    public <T extends Comparable> MyClass (T... values) { 
     this.values = new ArrayList<T>(); 
     for(T item : values) { 
      this.values.add(item); 
     } 
    } 

    public <T extends Comparable> List<T> getSortedLst() { 
     Collections.sort(this.values); 
     return this.values; 
    } 
} 

上加行錯誤:

Type mismatch: cannot convert from List<capture#4-of ? extends Comparable> to List<T> 

結論:

The method add(capture#2-of ? extends Comparable) in the type List<capture#2-of ? extends Comparable> is not applicable for the arguments (T) 

的排序行錯誤

看來,它似乎是Java不能完全處理wh在我想要做的事情上。問題是因爲什麼,我想說的是:

我想是 可比對自己的項目清單,我 從創建傳入的 數據一次創建整個列表。

但是,Java看到我有這個列表,並且無法確定我的情況的所有信息在編譯時是否可用,因爲我可以嘗試稍後將其添加到列表中,並且由於類型擦除,它不能保證安全。如果不將通用類型應用到類中,那麼與Java通信的情況實際上是不可能的。

+3

爲什麼不足以擁有一個實現Comparable的事物列表? – 2010-07-07 03:38:27

+0

並不是說它解決了這個問題,但是可比較的東西並不意味着它與它本身相比。只是實施Comparable並不是說「與自己相比」。 – RHSeeger 2010-07-07 04:31:49

+0

你可以用靜態方法來做到這一點。看到我的第二個答案。 – TofuBeer 2010-07-07 05:03:51

回答

7

我認爲簡單的答案是你不能那樣做。如果某個類屬性的類型取決於類型參數,則該參數必須在類級別聲明。我不認爲這是「有道理」的任何其他方式。

如果您的示例中的T不是該類的類型參數,它是什麼?它不能是方法的類型參數,因爲該類型由方法的調用方式決定。 (如果該方法被稱爲具有不同的推斷類型爲T不同的靜態背景下,是什麼在屬性聲明的背景下,名義類型的T?)

所以把這個還給你正試圖在這裏做,MyClass的一個實例將保存某種類型的元素,並且您希望能夠以靜態類型安全的方式插入和刪除元素。但同時你不想說出那種類型。那麼編譯器應該如何將靜態地區分出來,區分了一個MyClass實例,該實例持有(說)Integer對象和一個持有String對象的實例?

我甚至不認爲你可以用顯式動態類型檢查來實現這一點。 (我認爲這類型擦除意味着,getSortedList()方法的實現不能找出什麼實際類型綁定到它的返回類型。)

號真正的解決辦法是讓MyClass一個泛型類聲明的類型參數T ;例如

public class MyClass <T extends Comparable<T>> { 

並取出方法級類型參數T從兩種方法的聲明。

+0

我同意T在這段代碼中沒有任何上下文,但這是問題所在。我想要做的就是「有一個可以與自身比較的類型列表,以便我可以對其進行分類」。這顯然比聽起來不像通用的類更難。 – RHSeeger 2010-07-07 04:12:41

+0

這只是艱難的(實際上是不可能的),因爲你試圖避免使課程本身成爲通用的。 – 2010-07-07 04:26:51

+0

雖然如此。從概念上講,這個類不是通用的。當然,我可以讓類通用來解決問題,但我希望有一種方法可以避免它,因爲它是一種代碼味道。可能是語言所要求的,但是代碼味道。 – RHSeeger 2010-07-07 04:30:01

1

考慮像這樣(我所要說的話是不是現實,但它說明了爲什麼你需要做的,你需要做的事。):

class Foo<T> 
{ 
    private T value; 

    T getValue() { return value; } 
    void setValue(T val) {value = val; } 
} 

// some code that uses the above class 

Foo<Integer> iFoo = new Foo<Integer>(); 
Foo<String> sFoo = new Foo<String>(); 
iFoo.setValue(5); 
sFoo.setValue("Hello"); 

發生這種情況時,編譯器(不!真正做什麼,我要說的話)生成以下代碼:

class IntegerFoo 
{ 
    private Integer value; 

    Integer getValue() { return value; } 
    void setValue(Integer val) {value = val; } 
} 

class StringFoo 
{ 
    private String value; 

    String getValue() { return value; } 
    void setValue(String val) {value = val; } 
} 

// some code that uses the above class 

IntegerFoo iFoo = new IntegerFoo(); 
StringFoo< sFoo = new StringFoo(); 
iFoo.setValue(5); 
sFoo.setValue("Hello"); 

如果你能有實例變量/方法的參數不參數化類以上的事情(這是不太現實)止跌」工作。

你想要做什麼應該可以用靜態方法,但我不認爲這是你想要的。

你能解釋你爲什麼要做你想要做的代碼嗎?也許我們可以想出一個更好的方法來做你想做的事,在語言中起作用。

+0

我在它想要做的事情上添加了更多細節。簡而言之,我有一個成員變量,它是我想要排序的列表,但可以是任何單個(可排序)類型的列表。這個類本身不是一個「那種類型」的類,本身就是這個變量。 – RHSeeger 2010-07-07 04:28:24

+0

像新的MyClass (Integer.class,.........);並不罕見。 – TofuBeer 2010-07-07 04:34:54

1

我相信以下將達到你想要的(比較強的打字)。這將阻止人們將不是來自您的界面的Comparable對象添加到列表中,並允許多個實現。

public class test<T extends ComparableType> { 


final List<T> values = new ArrayList<T>(); 
    public test (T... values) { 
     for(T item : values) { 
      this.values.add(item); 
     } 
    } 

    public List<T> getSortedLst() { 
     Collections.sort(this.values); 
     return Collections.unmodifiableList(this.values); 
    } 
} 

public interface ComparableType extends Comparable<ComparableType> {} 

public class ConcreteComparableA implements ComparableType { 
    @Override 
    public int compareTo(ComparableType o) { 
    return 0; 
    } 
} 

public class ConcreteComparableB implements ComparableType { 
    @Override 
    public int compareTo(ComparableType o) { 
    return 0; 
    } 
} 

編輯:

我知道這可能是顯而易見的;但是,如果你不希望類是通用的這一解決方案也將一起工作:

public class test { 
    final List<ComparableType> values = new ArrayList<ComparableType>(); 

    public test (ComparableType... values) { 
     for(ComparableType item : values) { 
      this.values.add(item); 
     } 
    } 

    public List<ComparableType> getSortedLst() { 
     Collections.sort(this.values); 
     return Collections.unmodifiableList(this.values); 
    } 
} 
+0

您仍然在那裏使用泛型類,再加上您刪除了使用系統類(如String)創建實例的功能。 – RHSeeger 2010-07-07 04:33:31

+0

編輯表明,如果主要類不是通用的,它可以輕鬆工作。我相信目標是隻有經批准的可比較數據才能被使用(即字符串不可用於設計)。 – Syntax 2010-07-07 04:38:10

2

有大量在這個unchecked警告,但在原則上沒有必要保持List的任何東西,但包含一些事情你知道是Comparable。你在構造函數中執行你需要的規則,其他一切都應該沒問題。怎麼樣是這樣的:

public class MyClass { 

    final private List<Comparable> values; 

    public <T extends Comparable<? super T>>MyClass(T... values){ 
     this.values = new ArrayList<Comparable>(); 
     for(T item : values) { 
      this.values.add(item); 
     } 
    } 

    public <T extends Comparable<? super T>> List<T> getSortedLst() { 
     Collections.sort(this.values); 
     return (List<T>)this.values; 
    } 

} 

快速測試使用下面的顯示,實現可比類(如Integer和String)MyClass行爲與預期相同,但會拋出一個編譯錯誤,對於不落實Comparable類:

class Junk { } 

    public static void main(String[] args){ 
     MyClass s = new MyClass(1,2,3); 
     System.out.println(s.getSortedLst()); 

     MyClass a = new MyClass("c", "a", "b"); 
     System.out.println(a.getSortedLst()); 

     MyClass c = new MyClass(new Junk()); 
    } 
+0

這是非常接近我正在尋找。這就是說,還有另一個難題(有點相關,但使它比我想要處理的任務更復雜),當我這樣做的時候,它會讓我咬牙切齒。不過,我很欣賞這個答案。 – RHSeeger 2010-07-07 04:42:30

+0

@RHSeeger,因爲這基本上回答你的問題,我會欣賞更多的信息,爲什麼它是不夠的... – 2010-07-07 04:52:09

+0

主要問題是,我真的想要成員變量,說:「一些實現類比自己的類型」,而是不僅僅是「某種實現可比較的類型」,對於自我記錄代碼和其他需要這種值作爲輸入的代碼片段一樣。話雖如此,我也討厭看到未經檢查的警告,我的私人見解更多的是Java的糟糕設計。 – RHSeeger 2010-07-07 14:41:53

-1
public class MyClass<T extends Comparable<? super T>> { 
    // This doesn't work as T isn't defined 
    final List<T> values; 

    public MyClass (T... values) { 
     this.values = new ArrayList<T>(Arrays.asList(values)); 
    } 

    public List<T> getSortedLst() { 
     Collections.sort(this.values); 
     return this.values; 
    } 
} 
1

我會做這種方式(我做了一個列表或數組),除非你真的需要的實例變量/方法:

import java.lang.reflect.Array; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Collections; 
import java.util.List; 


public class MyClass 
{ 
    public static <T extends Comparable<T>> List<T> asSortedList(final T ... vals) 
    { 
     final List<T> temp; 

     temp = new ArrayList<T>(vals.length); 
     temp.addAll(Arrays.asList(vals)); 
     Collections.sort(temp); 

     return (Collections.unmodifiableList(temp)); 
    } 

    public static <T extends Comparable<T>> T[] asSortedArray(final Class<?> clazz, 
                   final T ... vals) 
    { 
     final T[] temp; 

     temp = (T[])Array.newInstance(clazz, 
           vals.length); 
     System.arraycopy(vals, 
         0, 
         temp, 
         0, 
         vals.length); 
     Arrays.sort(temp); 

     return (temp); 
    } 

    public static void main(final String[] argv) 
    { 
     final List<String> list; 
     final String[]  array; 

     list = MyClass2.asSortedList("c", "a", "b"); 
     System.out.println(list); 

     array = MyClass2.asSortedArray(String.class, "z", "y", "x"); 
     System.out.println(Arrays.deepToString(array)); 
    } 
} 
0

您想要的變量類型約束不能直接表示。你可以引入一個新的類型來彌補這個問題。

static class MyList<T extends Comparable<? super T>> extends ArrayList<T>{} 

final MyList<?> values; 

然而,在私人代碼段中沒有必要是非常安全的。泛型是幫助你澄清你的類型,而不是混淆它們。