2012-02-24 27 views
3

我喜歡這個 -Java的使用泛型返回不止一種類型

public List<Apples> returnFruits(String arg1){ 
List<Apples> fruits = new ArrayList<Apples>(); 
Apple a = new Apple(); 
fruits.add(a); 

return fruits; 
} 

我想改變它,這樣我可以從指定的方法調用的果型,並返回水果的方法名單。所以第二條語句應該動態實例化我傳遞的水果列表。我想到了這一點 -

public List<?> returnFruits(String arg1){ 
List<T> fruits = new ArrayList<T>(); 
T t = new T(); 
fruits.add(t); 

return fruits; 
} 

但是不知道正確的做法,如你所見。

在第二種方法中,我只返回水果代替列表 -

public T returnFruit(){ 
T t = new T(); 
return t; 
} 
所傳遞的水果是不是在同一個類層次和不同類型。

謝謝。

回答

4

您可以採取多種方法。其中一個是像其他人所建議的那樣使用Class<T>。另一個辦法是建立某種形式的生產接口,並通過在:

public interface FruitProducer<T> { 
    T createFruit(String arg); 
} 

public <T> List<T> returnFruits(String arg, FruitProducer<? extends T> producer) { 
    List<T> list = new ArrayList<T>(); 
    T fruit = producer.createFruit(arg); 
    list.add(fruit); 
    return list; 
} 

您有不同的水果不同的生產商:AppleProducer implements FruitProducer<Apple>OrangeProducer implements FruitProducer<Orange>等。這種方法只是將罐頭踢了一下 - FruitProducer仍然必須以某種方式創造果實 - 但它可能是一個有用的重構。

另一種方法依賴於相同的多態性作爲FruitProducer方法通過使類returnFruits摘要:

public abstract class FruitLister<T> { 
    public abstract List<T> returnFruits(String arg); 
} 

現在你有不同的製表:AppleLister implements FruitLister<Apple>等。每個知道如何實例化特定的類它需要返回列表中:

public class AppleLister implements FruitLister<Apple> { 
    @Override 
    public List<Apple> returnFruits(String arg) { 
      List<Apple> list = new ArrayList<Apple>(); 
      Apple apple = new Apple(arg); 
      list.add(apple); 
      return list; 
    } 
} 
2

Java通過擦除來實現泛型,所以在運行時沒有你傳入的泛型的概念。也不可能讓泛型類​​型爲new,因爲你不能保證傳入的類型將有一個無參數的構造函數。

您可以在類本身傳遞作爲一個真正的參數:

public <T> List<T> returnFruits(String arg1, Class<T> clazz){ 

...但你需要使用反射來實例化類的一個新版本,只需用你的手指希望用戶不提供沒有默認構造函數的類。

6

如果你肯定知道你有一個無參數的構造函數,你可以使用這個語法:

public <T> List<T> returnFruits(Class<T> clazz){ 
    List<T> fruits = new ArrayList<T>(); 
    T t = clazz.newInstance(); 
    fruits.add(t); 

    return fruits; 
} 

用法:

List<MyClass> m = returnFruits(MyClass.class, "plop"); 

如果你知道你有一個構造函數字符串參數:

public <T> List<T> returnFruits(Class<T> clazz, String arg1){ 
    List<T> fruits = new ArrayList<T>(); 
    Constructor<T> constructor = clazz.getConstructor(String.class); 
    T t = constructor.newInstance(arg1); 
    fruits.add(t); 

    return fruits; 
} 

用法:

List<MyClass> m = returnFruits(MyClass.class, "plop"); 

等等

+0

+1;我贊同你。不過,'clazz'有一個缺省構造函數(零參數)的風險。它會導致'newInstance'失敗。 – home 2012-02-24 15:29:20

+0

我同意。看看yshavit解決方案,在這裏提出一個使用界面生成器的優秀解決方案。 ;) – Nicocube 2012-02-24 16:12:40

+0

感謝您的解決方案。你有一個關於如何使用你的解決方案在對象類型上執行方法的想法。所以,如果Apple有方法設置顏色,我不認爲我可以說t.setColor();有沒有辦法調用這個函數?謝謝。 – Maryam 2012-02-24 20:04:23

0
<T> public List<T> returnFruit(){ 
Apple a = new Apple(); 
List<Apple> list = new ArrayList<Apple>; 
list.add(a); 
return list; 
} 

應該工作。基本上,聲明你需要在方法之前的類型「T」的列表。然後你可以返回任何類型的「T」列表。基本上,你不能做一個「新的T()」,因爲它沒有任何類型信息。它必須是一個混凝土類。

如果需要,甚至可以將該類的類型作爲參數傳遞。

+0

我對你的代碼進行了格式化,所以在每一行的開頭使用4個空格,所以SO將把這行代碼識別爲代碼。這樣你就不必編碼HTML/XML實體。 – home 2012-02-24 15:31:50

+0

甜!謝謝你的提示。會做。 :) – Pavan 2012-02-24 15:45:05