我有一个班级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()
?
答案 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
的所有非私有实例方法。相反,您可能知道不会覆盖字段。如果您在A
和B
中定义了具有相同名称的字段,则存在两个字段,其中B
中的子类字段超级字段中的字段A
中没有替换在A
中的使用。
内部类也是如此。这意味着A.Sub
和B.Sub
是两个不同的类,就像两个(假设的)字段A.foo
和B.foo
不同。 A.Sub
仅被B.Sub
遮蔽。因此,在new Sub()
内定义此调用时,调用A.Sub
将创建A
的实例,但在B.Sub
内定义时,会创建B
的实例。为了模拟多态性,您需要以某种方式获取涉及的方法调用以触发Java的动态调度。有两种方法可以做到这一点:
定义一个工厂方法,您可以覆盖它以创建所需的实例:
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
}
使A.Sub
到B.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;
}