1

我怎样才能拥有一个类的多个扩展Fruit,并根据对象是什么类/类型,在这个水果上执行相同的方法但具有不同的功能?

示例:我正在使用 a 向水果店FruitManager添加新的。Fruit fruit = new Apple();如果这个水果是苹果,我当然想把它添加到苹果列表中。香蕉清单也是如此。现在,如果我有 10 种水果,我不想创建 10 个函数,如addBanana(),addApple()等等。而且我也不想为了获得正确的水果清单而使用混乱的 if-else 语句。

我可以根据我添加的对象类型来获取水果列表吗?

class Fruit;
class Apple extends Fruit;
class Banana extends Fruit;

class FruitStore {
    List<Fruit> apples = new ArrayList<Apple>();
    List<Fruit> bananas = nwe ArrayList<Banana>();
}

class FruitManager {
    FruitStore store;

    //called from somewhere with Fruit fruit = new Apple();
    addFruit(Fruit fruit) {
        //how could things like this be done in one statement?
        store.<get list apples or bananas>.add(fruit);
    }
}
4

3 回答 3

5

把我的杂碎变成一个答案。考虑使用 HashMap HashMap<Class<? extends Fruit>, List<Fruit>>。像这样的东西:

class FruitStore {
   private Map<Class<? extends Fruit>, List<Fruit>> fruitMap = 
         new HashMap<Class<? extends Fruit>, List<Fruit>>();

   public void addFruit(Fruit fruit) {
      Class<? extends Fruit> fruitClass = fruit.getClass();
      List<Fruit> fruitList = fruitMap.get(fruitClass);
      if (fruitList == null) {
         fruitList = new ArrayList<Fruit>();
         fruitMap.put(fruitClass, fruitList);
      }
      fruitList.add(fruit);
   }

   public void displayStore() {
      for (List<Fruit> fruitList : fruitMap.values()) {
         System.out.println(fruitList);
      }
   }
}

我对此进行了测试:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FruitManager {
   public static void main(String[] args) {
      FruitStore fruitStore = new FruitStore();
      for (int i = 0; i < 20; i++) {
         if (i % 3 == 0) {
            fruitStore.addFruit(new Banana());
         } else {
            fruitStore.addFruit(new Apple());
         }
      }

      fruitStore.displayStore();
   }
}

abstract class Fruit {
   public abstract String getName();

   @Override
   public String toString() {
      return getName();
   }
}

class Apple extends Fruit {

   private static final String NAME = "Apple";

   @Override
   public String getName() {
      return NAME;
   }

}


class Banana extends Fruit {

   private static final String NAME = "Banana";

   @Override
   public String getName() {
      return NAME;
   }

}

class FruitStore {
   private Map<Class<? extends Fruit>, List<Fruit>> fruitMap = 
         new HashMap<Class<? extends Fruit>, List<Fruit>>();

   public void addFruit(Fruit fruit) {
      Class<? extends Fruit> fruitClass = fruit.getClass();
      List<Fruit> fruitList = fruitMap.get(fruitClass);
      if (fruitList == null) {
         fruitList = new ArrayList<Fruit>();
      }
      fruitList.add(fruit);
      fruitMap.put(fruitClass, fruitList);
   }

   public void displayStore() {
      for (List<Fruit> fruitList : fruitMap.values()) {
         System.out.println(fruitList);
      }
   }
}
于 2012-10-20T03:40:46.273 回答
1

虽然您可以避免对addBanana(..),addApple(..)等的需要,但如果没有几个 if-else 语句,这是不可行的,除非您想在使用反射时失去相当多的程序效率。

public void addFruit(Fruit fruit) {
    if (fruit instanceof Apple) {
        store.apples.add(fruit);
    } else if (fruit instance of Banana) {
        store.bananas.add(fruit);
    } else if ... { }
}

如果你真的想使用反射方法......这里是,但我不推荐它。

public void addFruit(Fruit fruit) {
    try {
        Class<Fruit> clazz = fruit.getClass();
        String clazzName = clazz.getName();
        String listName = clazzName.toLowercase() + "s";
        Class<FruitStore> fsClazz = store.getClass();
        Field listField = fsClazz.getDeclaredField(listName);
        listField.setAccessible(true);
        List<Fruit> list = (List<Fruit>) listField.get(store);
        list.add(fruit);
    } catch (Exception e) {
        // failed to add fruit
        e.printStackTrace();
    }
}

注意:反射方法未经测试,但我认为可能发生的唯一问题是Field#get返回对其值副本的引用而不是对其值的引用,从而导致list.add(fruit)添加到与类中的列表不同的列表中。

于 2012-10-20T03:16:33.217 回答
1
List<Fruit> apples = new ArrayList<Apple>();

首先,这在 Java 中是无效的,因为水果列表不能指向苹果列表,因为List<Fruit>它可能包含任何水果,即苹果或香蕉,而ArrayList<Apple>只能包含苹果。

其次,当您有这样的继承链时,通常不会将它们存储在单独的列表中。您可以将它们存储在一个列表中,List<Fruit>并且在此列表中的每个元素上执行的任何操作都将具有多态行为,并且根据 的实际类型Fruit,行为可能与相应类中定义的不同。

因此,您应该重新考虑您认为需要单独存储它们的用例。

于 2012-10-20T03:21:03.600 回答