2016-06-19 63 views
3

我想知道在泛型類或方法中使用接口(或超類型)和使用泛型方法與邊界之間有什麼區別(T extends Interface )。在方法和類中使用泛型和接口有什麼區別

比方說,我有實現和接口(幼稚的例子)兩大類:

public interface MeasurableDistance { 
    public Point getPosition(); 
} 

public class Person implements MeasurableDistance { 
    private Point position; 

    public Point getPosition() { 
     return position; 
    } 
} 

public class House implements MeasurableDistance { 
    private Point position; 

    public Point getPosition() { 
     return position; 
    } 
} 

1)會是怎樣通過以下方式編寫方法之間的區別:

public int computeDistance(MeasurableDistance a, MeasurableDistance b) { 
    Point a = a.getPosition(); 
    Point b = b.getPosition(); 
    //compute distance 
    return distance, 
} 

和類似的東西

public <T extends MeasurableDistance, S extends MeasurableDistance> int computeDistance(T a, S b) { 
    Point a = a.getPosition(); 
    Point b = b.getPosition(); 
    //compute distance 
    return distance, 
} 

2)如果我想要一個班舉行一個MeasurableDistanc Ë對象:

public class Holder { 
    private MeasurableDistance holder; 

    public Holder() {}; 
    public add(MeasurableDistance a) { 
     holder = a; 
    } 
} 

或類似

public class Holder<T extends MeasurableDistance> { 
    private T holder; 

    public Holder<T>() {}; 
    public add(T a) { 
     holder = a; 
    }; 
} 

對1,我想他們應該是非常相同的,對不對?顯然調用非通用版本

Person a = new Person(); 
Person b = new Person(); 
House c = new House(); 
House d = new House(); 
computeDistance(a,c); 
computeDistance(a,b); 
computeDistance(c,d); 

總是工作,因爲computeDistance()會看到這些對象是因爲多態性MeasurableDistance。通用版本應該工作得對嗎?編譯器會推斷MeasurableDistance類型並相應地添加轉換。即使我想打電話這樣說:

<Person, House>computeDistance(a,c); 

將有同樣的效果,該方法看起來像

Point a = (MeasurableDistance) a.getPosition(); 
    Point b = (MeasurableDistance) b.getPosition(); 

,如果我沒有記錯。或者,現在我想起它,它應該看起來像這樣:

Point a = (Person) a.getPosition(); 
    Point b = (House) b.getPosition(); 

它會工作,因爲Person和House都在實現該方法。

那麼通用方法的優點是什麼?我讀過它是類型安全的,因爲強制轉換總是正確的,但是對於非泛型方法,您根本不會執行強制轉換。

+1

1)在那裏使用泛型沒有意義。所有你需要的是一對'MeasurableDistance'實例。您可以使用泛型的唯一方法是如果您有一個與輸入相關的泛型參數(或泛型或非泛型返回)類型,例如'列表'。 –

+0

@JornVernee謝謝你,修好了! – Paul

+0

@AndyTurner你可以擴展你的評論嗎?第二部分尤其如此。謝謝! – Paul

回答

2

您似乎混淆了使用泛型的原因,以及使用有界泛型的原因。

使用有界的泛型的一個理由,意味着已經有使用泛型的理由。

讓我回顧一下。


使用泛型的原因在Java tutorials解釋,和最明顯的一個原因是這樣的:

沒有泛型下面的代碼片段需要鑄造:

List list = new ArrayList(); 
list.add("hello"); 
String s = (String) list.get(0); 

當重寫爲使用泛型時,代碼不需要強制轉換:

List<String> list = new ArrayList<String>(); 
list.add("hello"); 
String s = list.get(0); // no cast 

使用有界的泛型的原因與使用泛型的原因是分開的。 如果你有一個理由使用泛型,使用範圍讓您需要的類型的某種程度的功能:

public class MyClass<T> { 
    private List<T> list; 
    ... 
    public void disposeAll() { 
     for(T e : list) 
      e.dispose(); // compile time error 
    } 
} 

上述錯誤可以通過添加約束來解決:

public class MyClass<T extends Disposable> {...} 

您已經顯示的案例實際上沒有理由使用有界的泛型,就像您指出的那樣。但這是因爲他們首先沒有(好)理由使用泛型。

在案例2中,仿製藥讓你限制可以通過Holder舉行的對象類型:

Holder<House> holder = new Holder<>(); 
holder.add(new Person()); // compile time error 
holder.add(new House()); 

這是不是非常有用的。在那裏使用泛型沒有真正的理由。

但是,如果你還檢索值,仿製藥將是有益的:

Holder<House> holder = new Holder<>(); 
// holder.add(new Person()); 
holder.add(new House()); 
House h = holder.get(); // no cast 
2

首先,當你這樣定義

public <T extends MeasurableDistance, S extends MeasurableDistance> 
    int computeDistance(T a, S b) { 

    Point a = a.getPosition(); 
    Point b = b.getPosition(); 
    //compute distance 
    return distance, 
} 

的方法將有沒有類型轉換在所有。此方法將做同樣與方法簽名

public int computeDistance(MeasurableDistance a, MeasurableDistance b) 

這就是爲什麼一般類型參數在這裏做沒有意義的原因;他們不會改變任何東西。


作爲一個經驗法則,當你要聲明兩個或多個參數之間或參數(S)和返回類型之間的關係上的方法類型參數是有用的。

public <T extends MeasurableDistance> T validate(T a, Rectangle area) { 
    Point p = a.getPosition(); 
    if(!area.contains(p)) 
     throw new IllegalArgumentException(); 
    return a, 
} 

在這裏,我們有參數和返回值類型之間的關係,它允許使用使用它喜歡:

Person person; 
Rectangle localArea; 

public void setPerson(Person newPerson) { 
    this.person = validate(newPerson, localArea); 
} 

,因爲一般的簽名指定,當我們爲T替代Person,我們有傳入一個Person實例,並保證返回一個Person實例。


同樣,如果我們可以表示類的兩個或多個成員之間的關係,類的通用簽名是有用的。例如。一個List表示這樣的關係,我們addset是我們可以通過get檢索的相同類型的對象。

因此,當您添加一個方法來檢索封裝對象時,您的Holder類將是一個適當的用於類型參數的用例,因爲存儲和檢索方法之間存在關係。因此,這兩種方法之間還有一種關係,即保持該引用的成員變量的類型,這是正確實現邏輯所需的。

相關問題