在上一次转换为超类类型之后调用正确的子类方法



假设您有一个基类BC,其中包含子类SC1、SC2。。。以及对象的集合C(一些是SC1类型,一些是SC2类型,…)。方法m在子类中定义,而不是在BC中。我希望做这样的事情:

class AnotherClass {
  private BC getObj(Container c) { /*return something from c*/ }
  private void anotherMethod() {
    ...
    BC o = getObj(c);
    o.m();
  }
}

现在getObj将返回一个对对象的引用o,据我所知,它必须是BC类型(或者有没有方法在这里应用泛型?)。我得到了一个编译错误(m()在BC中不存在)。我想有一种很好的方法可以做到这一点(而不必以某种方式"手动"计算出o的真实类型)?

为什么BC中没有定义方法?这就是多态性的意义所在。

您的另一个选择是让对象实现一个包含m的接口,并拥有该接口的集合而不是BC。或者使用反射(ew),或者检查类型(ew)。

public class BC 
{
    protected void m()
    {
        System.out.println("BC:M");
    }
}

public class SC1 extends BC 
{
    public void m()
    {
        super.m();
        System.out.println("SC1:M");
    }
}

public class SC2 extends BC 
{
    public void m()
    {
        super.m();
        System.out.println("SC2:M");
    }
}

public class TestClass 
{
    public static void main(String args[])
    {
        SC1 sc1_one= new SC1();
        SC1 sc1_two= new SC1();
        SC2 sc2_one= new SC2();
        SC2 sc2_two= new SC2();
        ArrayList al = new ArrayList<BC>();
        al.add(sc1_one);
        al.add(sc2_one);
        al.add(sc1_two);
        al.add(sc2_two);
        BC bc = (BC) al.get(3);
        bc.m();
    }
}

输出:BC:MSC2:M

对于这些场景,您需要在基类中声明方法m。然后您可以覆盖到子类

此时

BC o = getObj(c);

你有一个对象的引用。在编译时,您的代码唯一知道的事实是,无论这个引用指向什么(BC,或BC的子类),都有在BC中定义的方法。它不知道你给它的子类是SC1或SC2的实例。因此,您的问题是需要执行仅在子类上定义的方法。这里有几个选项。

  1. 反射-使用Java的反射功能来检查给定的对象,看看该方法是否可用,然后调用它。但您会失去编译时的检查,而且速度很慢。不是首选解决方案
  2. 检查c的实例,转换为适当的类型,然后调用这些方法。这将起作用,但instanceof也很慢,并且无法实现子类化和多态性的目的。也不推荐
  3. 在BC中引入一个方法(如果BC从不需要实例化,则可能是抽象的),然后子类覆盖该方法。直接调用此方法。这是一个更好的解决方案,可能也是你应该追求的
  4. 如上所述,但是使用子类实现的接口,并让方法返回该接口

最新更新