我有一个抽象的超类
public abstact class SuperClass
2个类扩展了这个超类
public class ChildClass1 extends SuperClass
public class ChildClass2 extends SuperClass
我有一个arraylist
List<SuperClass> objects = new ArrayList<SuperClass>();
我有一个方法有2个不同的参数列表
public void get(ChildClass1 o)
public void get(ChildClass2 o)
尝试这样的事情时:
for (SuperClass o : objects)
get(o);
我收到错误:“方法get()不适用于参数SuperClass”
我应该如何实现这一点,列表中的每个元素都可以调用正确的方法?我可以实现这一点的唯一方法是使用instanceof并将其转换,还是有更好的方法?
答案 0 :(得分:0)
这是不可能的,因为Java在编译时决定使用哪种方法。您可以在SuperClass中定义一个get方法,然后代码如下所示:
for (SuperClass o : objects)
o.get();
快速Stackoverflow搜索引导我进入此主题,您可以获得更多信息:overloading and compile time binding。有人建议在那里使用访客模式。这也许是另一种选择。当每个Java开发人员遇到你迟早要问的问题时,我确信在Stackoverflow上可以找到关于这个主题的很多有趣的线程。
答案 1 :(得分:0)
Java(大多数)方法调用动态地绑定到调用它们的对象,但它静态地确定类型签名。因此,当你的代码......
for (SuperClass o : objects)
get(o);
...在编译时进行分析,Java必须仅根据当时的信息选择get()
方法签名,即o
是SuperClass
。此外,它将为相关类的现有方法选择一个方法签名。在运行时,它将针对调用它的对象的类解析该方法签名,仅考虑支持协变返回类型所需的其他签名。
您有这样的要求会产生明显的代码气味。收集List<SuperClass>
中的对象仅用于任何SuperClass
同样良好(并且可能是多态)服务的目的是有意义的,但事实并非如此。如果您无法改变设计的这一方面,那么有多种方法可以继续,包括......
丑陋的黑客行为
使用instanceof
并投射:
for (SuperClass o : objects) {
if (o instanceof ChildClass1) {
get((ChildClass1) o);
} else if (o instanceof ChildClass2) {
get((ChildClass2) o);
} else if (o == null) {
// do something appropriate
} else {
throw new SomeKindOfException(
"Don't know what to do with a " + o.getClass());
}
}
双重控制/控制反转
为超类提供方法......
abstract void acceptGetter(ClassThatGets objectThatGets);
...并让每个子类以相同的方式实现它:
void acceptGetter(ClassThatGets objectThatGets) {
objectThatGets.get(this);
}
然后用......替换你有问题的循环
for (SuperClass o : objects)
o.acceptGetter(this);
...假设该代码出现在类ClassThatGets
中,它声明了您描述的get()
方法,或者声明该类的子类。
肯定还有其他替代品,其中一些可能更适合您的整体设计。