来自polymorph列表的Java原始类方法调用

来自polymorph列表的Java原始类方法调用,java,list,arraylist,polymorphism,overloading,Java,List,Arraylist,Polymorphism,Overloading,我有一个抽象的超类 public abstact class SuperClass public class ChildClass1 extends SuperClass public class ChildClass2 extends SuperClass 2个类扩展了这个超类 public abstact class SuperClass public class ChildClass1 extends SuperClass public class ChildClass2 exten

我有一个抽象的超类

public abstact class SuperClass
public class ChildClass1 extends SuperClass
public class ChildClass2 extends SuperClass
2个类扩展了这个超类

public abstact class SuperClass
public class ChildClass1 extends SuperClass
public class ChildClass2 extends SuperClass
我有一个数组列表

List<SuperClass> objects = new ArrayList<SuperClass>();
当尝试这样的事情时:

for (SuperClass o : objects)
    get(o);
for (SuperClass o : objects)
  o.get();
我得到一个错误:“get()方法不适用于参数超类”


我应该如何实现这一点,使列表中的每个元素都能调用正确的方法?我实现这一点的唯一方法是使用instanceof并强制转换它,还是有更好的方法?

这是不可能的,因为Java在编译时决定使用哪种方法。您可以在超类中定义一个get方法,然后代码如下所示:

for (SuperClass o : objects)
    get(o);
for (SuperClass o : objects)
  o.get();
快速Stackoverflow搜索将引导我找到此线程。有更多信息可供您使用:。有人提议在那里使用访问者模式。这也可能是另一种选择。每个Java开发人员迟早都会遇到您提出的问题,我相信在Stackoverflow上可以找到很多关于这个主题的有趣的线程。

Java动态地绑定(大多数)方法调用,但它静态地确定类型签名。因此,当您的代码

for (SuperClass o : objects)
    get(o);
。。。在编译时进行分析时,Java必须仅基于它当时拥有的信息来选择
get()
方法签名,即
o
是一个
超类。此外,它将为相关类上的现有方法选择一个方法签名。在运行时,它将根据调用它的对象的类解析该方法签名,只考虑支持协变返回类型所需的其他签名

您有这样的需求会产生一种独特的代码气味。收集
列表
中的对象只用于任何
超类
都同样有效(可能是多态性)的目的是有意义的,但您不适合这种情况。如果您无法更改设计的这一方面,那么有多种方法可以继续,包括


一种丑陋的黑客方式

使用
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()
方法,或者出现在该类的子类中



当然还有其他选择,其中一些可能更适合您的总体设计。

为什么在同一列表中存储这两种类型的数据很重要?如果它们都在自己的列表中,您可以使用实数类型并避免这种情况。哪个方法是正确的?您能使
get
成为
SuperClass
的实例方法吗?我不能,因为它们根据参数的子类返回不同的类实例(具有与这些相同的结构)