如何对类Fruit
进行多次扩展,并根据对象所属的类/类型,在此水果上执行相同的方法,但具有不同的功能?
示例:我正在使用FruitManager
向fruitstore添加新的Fruit fruit = new Apple();
。如果这个水果是苹果,我当然希望将其添加到苹果列表中。 Elso到香蕉列表。
现在,如果我有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);
}
}
答案 0 :(得分:5)
让我的kludge成为答案。考虑使用HashMap<Class<? extends Fruit>, List<Fruit>>
的HashMap。像这样:
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);
}
}
}
答案 1 :(得分: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)
添加到与班级中的列表不同的列表。
答案 2 :(得分:1)
List<Fruit> apples = new ArrayList<Apple>();
首先,这在Java中无效,因为水果列表无法指向苹果列表,因为List<Fruit>
可能包含任何水果,即苹果或香蕉,而ArrayList<Apple>
只能包含苹果。
其次,当你有这样的继承链时,通常不会将它们存储在单独的列表中。您可以将它们存储在单个列表List<Fruit>
中,并且对此列表中的每个元素执行的任何操作都将具有多态行为,并且基于Fruit
的实际类型,行为可能会有所不同,在相应的类中定义。
因此,您应该重新考虑您认为需要单独存储它们的用例。