Java原始类方法从多态列表调用

时间:2015-11-18 18:25:46

标签: java list arraylist polymorphism overloading

我有一个抽象的超类

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并将其转换,还是有更好的方法?

2 个答案:

答案 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()方法签名,即oSuperClass。此外,它将为相关类的现有方法选择一个方法签名。在运行时,它将针对调用它的对象的类解析该方法签名,仅考虑支持协变返回类型所需的其他签名。

您有这样的要求会产生明显的代码气味。收集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()方法,或者声明该类的子类。

肯定还有其他替代品,其中一些可能更适合您的整体设计。