使用子类中的重写方法

时间:2014-11-21 10:27:15

标签: java inheritance

我有一个班级A

private static class A 
{
  public void foo() 
  {
    Sub sub = new Sub();
    sub.bar();
  }

  protected class Sub 
  {
    protected void bar() 
    {
      System.out.println("bar from A");
    }
  }
}

我想将其扩展为稍微修改其子类bar()中的Sub

private static class B extends A 
{
  protected class Sub extends A.Sub 
  {
    @Override
    protected void bar() 
    {
      System.out.println("bar from B");
    }
  }
}

如果我现在试着打电话

B b = new B();
b.foo();

我从A 获得栏,但我需要来自B 栏。

我也可以解决覆盖foo()的问题。但foo()是一个很大的方法,如果我只是复制它,我会得到冗余代码。我不能将它分成多个较小的。

是否可以在不覆盖bar()的情况下调用新的foo()

3 个答案:

答案 0 :(得分:2)

A.foo()中,您正在创建A.Sub的实例。这就是调用bar()的{​​{1}}而不是A.Sub的{​​{1}}的原因。

一种可能的解决方案是替换

bar()

with:

B.Sub

然后在A:

Sub sub = new Sub();

在B:

Sub sub = getSub();

protected Sub getSub() { return new Sub(); } 的实例会生成@Override protected Sub getSub() { return new Sub(); } 的实例,而B的实例会生成B.Sub的实例。

答案 1 :(得分:1)

你正在努力解决一个相当尴尬的Java语言概念called shadowing。您知道,在B extends A之后,您将覆盖A中定义的B的所有非私有实例方法。相反,您可能知道不会覆盖字段。如果您在AB中定义了具有相同名称的字段,则存在两个字段,其中B 中的子类字段超级字段中的字段A中没有替换A中的使用。

内部类也是如此。这意味着A.SubB.Sub是两个不同的类,就像两个(假设的)字段A.fooB.foo不同。 A.Sub仅被B.Sub遮蔽。因此,在new Sub()内定义此调用时,调用A.Sub将创建A的实例,但在B.Sub内定义时,会创建B的实例。为了模拟多态性,您需要以某种方式获取涉及的方法调用以触发Java的动态调度。有两种方法可以做到这一点:

  1. 定义一个工厂方法,您可以覆盖它以创建所需的实例:

    class A {
       class Sub { void doSomething() { 
         System.out.println("A.Sub"); } 
       }
       Sub make() { return new Sub(); } // Returns B.Sub
    }
    class B extends A {
       class Sub extends A.Sub { // Shadows A.Sub
         void doSomething() { System.out.println("B.Sub"); 
       }
       @Override
       Sub make() { return new Sub(); } // Returns B.Sub, also when called within A
    }
    
  2. 使A.SubB.Sub层次结构多态:

    class A {
       class Sub { 
         void invoke() { doSomething(); } // Invokes outer method virtually
       }
       void doSomething() { System.out.println("A"); }
    }
    class B extends A {
       class Sub extends A.Sub { }  // Shadows A.Sub
       @Override
       void doSomething() { System.out.println("B"); }
    }
    

答案 2 :(得分:0)

您需要在对象中注入Sub才能实现此目的。如果您将其放在类A构造函数中,则只能看到A.Sub

然后,为A创建一个接受A.Sub和子类的构造函数:

public A(Sub sub) {
  this.sub = sub;
}