如何防止Java Generics强制重复代码?

时间:2014-05-02 15:22:48

标签: java variables generics duplicates

我试图编写一个AnimalGroup工厂类,它返回一个包含各种不同类型Animal的实例。不幸的是,由于Java泛型的限制,我被迫重复代码。我已经尝试了所有可能的通配符组合,我可以想到没有运气。

以下是代码:

public AnimalGroup<?> getAnimalGroup (String animalName) {
    if(animalName.equals("Yetti")) {
        AnimalGroup<Yetti> animalGroup = new AnimalGroup<>(Yetti.class);
        animalGroup.doSomeProcessing();
        return animalGroup;
    }
    else {
        AnimalGroup<Doge> animalGroup = new AnimalGroup<>(Doge.class);
        animalGroup.doSomeProcessing();
        return animalGroup;
    }
}

这是我想做的事情:

public AnimalGroup<?> getAnimalGroup (String animalName) {
    Class<?> animalClass = Doge.class;

    if(animalName.equals("Yetti")) {
        animalClass = Yetti.class;
    }

    AnimalGroup<animalClass> animalGroup = new AnimalGroup<>(animalClass);
    animalGroup.doSomeProcessing();
    return animalGroup;
}

更新:

使用<? extends Animal>解决方案,以下附加处理代码不再有效:

// Pseudo-ish code
public <T extends Animal> void setAnimals (T animals) { this.animals = animals; }

List<? extends Animal> animals = getAnimals(animalClass);
animalGroup.setAnimals(animals);

给出的错误令人困惑:

setAnimals(java.util.List<capture<? extends Animal>>) in AnimalGroup cannot be applied to (java.util.List<capture<? extends Animal>>)

任何帮助都很大。谢谢! 本。

4 个答案:

答案 0 :(得分:1)

Doge和Yeti是否扩展了相同的Animal类?如果是,那么你可以做

 public AnimalGroup<? extends Animal> getAnimalGroup (String animalName) {
    Class<? extends Animal> animalClass = Doge.class;

    if("Yetti".equals(animalName)) {
        animalClass = Yetti.class;
    }

    AnimalGroup<? extends Animal> animalGroup = new AnimalGroup<>(animalClass);
    animalGroup.doSomeProcessing();
    return animalGroup;
    }

如果他们没有,那么他们应该:)。

我无法理解编辑我做了POC并且以下代码有效(假设接口A并实现类B和C:

private static List<? extends A> generateObjects(boolean isItB) {
        if (isItB) {
            return new ArrayList<B>() {
                {
                    add(new B());
                }
            };
        } else {
            return new ArrayList<C>() {
                {
                    add(new C());
                }
            };
        }
    }

    private static void consumeObjects(List<? extends A> consuming) {
        for (A a : consuming) {
            a.doStuff();
        }
    }

    public static void main(String[] args) {
        List<? extends A> generatedBs = generateObjects(false);
        consumeObjects(generatedBs);


    }

答案 1 :(得分:1)

您可以尝试enum

class AnimalGroup<T> {

    AnimalGroup(Class<T> itsClass) {

    }

    public void doSomeProcessing() {

    }
}

class Yetti {

}

class Dog {

}

// Connects the name of the animal with the 
enum Animal {

    Dog(Dog.class),
    Yetti(Yetti.class),
    // Can also have aliases this way.
    AbominableSnowman(Yetti.class);
    final Class itsClass;

    Animal(Class c) {
        itsClass = c;
    }
}

public AnimalGroup<?> getAnimalGroup(String animalName) {
    Animal animal = Animal.valueOf(animalName);
    AnimalGroup<?> g = new AnimalGroup<>(animal.itsClass);
    g.doSomeProcessing();
    return g;
}

答案 2 :(得分:1)

您可以尝试在没有使用参数化泛型方法的纯泛型的String类名的情况下执行此操作:

class Wrapper {

   public <T> AnimalGroup<T> getAnimalGroup (Class<T> cl) {   

       AnimalGroup<T> animalGroup = new AnimalGroup<T>(cl);
       animalGroup.doSomeProcessing();
       return animalGroup;               
   }
}

然后,AnimalGroup和Animal类可能如下所示:

   class AnimalGroup<T> {
       private Class<T> cl;

       public AnimalGroup(Class<T> cl) {
           this.cl = cl;
       }

       public void doSomeProcessing() {
           System.out.println(cl);
        /*
        here i just printout the classname, but you can do proccessing like this
        if (cl.equals(Yetti.class)) do one thing, else do another, etc.            
        */
       }
    }

    class Yetti{}

    class Dog{}

一个简单的测试:

public class HelloWorld{

     public static void main(String []args){
        Wrapper an = new Wrapper();
        an.getAnimalGroup(Yetti.class);
        //new AnimalGroup<String>(String.class).doSomeProcessing();

     }
}

返回以下输出

class Yetti

如您所见,您的动物根据存储在AnimalGroup类的Class cl变量中的类型进行区分。

答案 3 :(得分:1)

以下是使用查找Map<String, Class<? extends Animal>>的解决方案:

private static Map<String, Class<? extends Animal>> map = new HashMap<String, Class<? extends Animal>>() {
    {
        put("Yetti", Yetti.class);
        put("Doge", Doge.class);
    }
};

public static AnimalGroup<? extends Animal> getAnimalGroup(String animalName) {
    AnimalGroup<? extends Animal> animalGroup = new AnimalGroup<>(map.get(animalName));
    animalGroup.doSomeProcessing();
    return animalGroup;
}