2012-02-24 3 views
3

У меня есть метод, как this-ява Использование дженериков возвращать более одного типа

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

return fruits; 
} 

Я хотел бы изменить его, так что я могу определить тип фруктов из вызова метода и возвращает этот фрукт список. Таким образом, 2-й оператор должен динамически создавать список фруктов, которые я передаю. Я подумал об этом:

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

return fruits; 
} 

Но не знаю, как правильно это сделать, как вы можете видеть.

Во втором методе, я просто вернуть фрукты вместо list-

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

Теперь у вас есть различный Listers: 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"); 

Etc.

+0

+1; Я с тобой согласен. Тем не менее существует риск того, что 'clazz' не имеет конструктора по умолчанию (нулевой аргумент). Это приведет к сбою 'newInstance'. – home

+0

Согласен. давайте взглянем на решение yshavit здесь, предложим отличное решение с построителем интерфейса. ;) – Nicocube

+0

Спасибо за ваше решение. У вас есть идея, как я могу выполнить метод по типу объекта с помощью вашего решения. Итак, если у Apple есть метод, задающий цвет, я не думаю, что могу сказать t.setColor(); Есть ли способ вызвать эту функцию? Благодарю. – Maryam

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

Я отформатировал ваш код, ust использует 4 пробела в начале каждой строки, и SO распознает эту строку как код. Таким образом, вам не нужно кодировать элементы HTML/XML. – home

+0

Sweet! Спасибо за совет. Сделаю. :) – Pavan

Смежные вопросы