Java-使用泛型返回多种类型

时间:2012-02-24 15:15:16

标签: java generics methods return

我有这样的方法 -

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 个答案:

答案 0 :(得分: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");

如果您知道有一个带String参数的构造函数:

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");

答案 1 :(得分: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);
}

现在你有不同的lister: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 :(得分:2)

Java通过擦除实现泛型,因此在运行时没有传递您传入的泛型类型的概念。也不可能new泛型类型,因为您不能保证传入的类型将具有无参数构造函数。

您可以将类本身作为一个真实参数传递:

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

...但是你需要使用反射来实例化该类的新版本,并且只需要指责用户不要提供没有默认构造函数的类。

答案 3 :(得分:0)

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

应该有效。基本上,声明在方法之前需要一个类型为“T”的列表。然后,您可以返回任何类型“T”的列表。基本上,你不能做“新T()”,因为它没有任何类型信息。它必须是一个混凝土类。

如果需要,您甚至可以将该类类型作为参数传递。