2014-11-21 14 views
2

重写的方法我有一个类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(); 

我从一个栏调用它,但我需要的B吧。

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

有没有办法调用新的bar()而不是覆盖foo()

回答

2

A.foo()要创建的A.Sub一个实例。这就是为什么bar()A.Sub被调用,而不是bar()B.Sub

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

Sub sub = new Sub();

与:

Sub sub = getSub();

然后在:

protected Sub getSub() 
{ 
    return new Sub(); 
} 

而在B:

@Override 
protected Sub getSub() 
{ 
    return new Sub(); 
} 

B实例将产生B.Sub实例而A实例将产生A.Sub一个实例。

0

您需要在对象中注入Sub以实现此目的。如果你让它在A构造函数中,它只能看到A.Sub

然后,做出A一个构造函数,接受一个A.Sub和子类:

public A(Sub sub) { 
    this.sub = sub; 
} 
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中定义此调用时创建A.Sub的实例,但在B中定义时创建B.Sub的实例。为了模拟多态性,您需要以某种方式获得涉及的方法调用,以触发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"); } 
    }