首页 > 解决方案 > Java中包可见性的继承

问题描述

我正在寻找以下行为的解释:

以下是课程:

package a;

public class A {
    void m() { System.out.println("A"); }
}

// ------ 

package b;

import a.A;

public class B extends A {
    void m() { System.out.println("B"); }
}

// ------ 

package c;

import b.B;

public class C extends B {
    void m() { System.out.println("C"); }
}

// ------ 

package a;

import c.C;

public class D extends C {
    void m() { System.out.println("D"); }
}

// ------ 

package b;

import a.D;

public class E extends D {
    void m() { System.out.println("E"); }
}

// ------ 

package c;

import b.E;

public class F extends E {
    void m() { System.out.println("F"); }
}

主要课程在package a

package a;

import b.B;
import b.E;
import c.C;
import c.F;

public class Main {

    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        C c = new C();
        D d = new D();
        E e = new E();
        F f = new F();

        System.out.println("((A)a).m();"); ((A)a).m();
        System.out.println("((A)b).m();"); ((A)b).m();
        System.out.println("((A)c).m();"); ((A)c).m();
        System.out.println("((A)d).m();"); ((A)d).m();
        System.out.println("((A)e).m();"); ((A)e).m();
        System.out.println("((A)f).m();"); ((A)f).m();

        System.out.println("((D)d).m();"); ((D)d).m();
        System.out.println("((D)e).m();"); ((D)e).m();
        System.out.println("((D)f).m();"); ((D)f).m();
    }
}

这是输出:

((A)a).m();
A
((A)b).m();
A
((A)c).m();
A
((A)d).m();
D
((A)e).m();
E
((A)f).m();
F
((D)d).m();
D
((D)e).m();
D
((D)f).m();
D

这是我的问题:

1)我知道D.m()hides A.m(),但是演员A应该暴露 hiddenm()方法,这是真的吗?还是尽管打破了继承链,但还是会被D.m()覆盖?A.m()B.m()C.m()

((A)d).m();
D

2)更糟糕的是,下面的代码显示了覆盖效果,为什么?

((A)e).m();
E
((A)f).m();
F

为什么不在这部分:

((A)a).m();
A
((A)b).m();
A
((A)c).m();
A

和这个?

((D)d).m();
D
((D)e).m();
D
((D)f).m();
D

我正在使用 OpenJDK javac 11.0.2。


编辑:第一个问题由如何覆盖具有默认(包)可见性范围的方法来回答?

在类 D 中声明或继承的实例方法 mD,从 D 覆盖在类 A 中声明的另一个方法 mA,如果以下所有条件都为真:

  • A 是 D 的超类。
  • D 不继承 mA(因为跨越封装边界)
  • mD 的签名是 mA 签名的子签名(第 8.4.2 节)。
  • 以下情况之一是正确的:[...]
    • mA 在与 D 相同的包中声明为具有包访问权限(本例),并且 D 声明 mD 或 mA 是 D 的直接超类的成员。 [...]

但是:第二个问题仍未解决。

标签: javainheritanceoverridingshadowingpackage-private

解决方案


我知道D.m()hides A.m(),但是演员A应该暴露 hiddenm()方法,是真的吗?

没有隐藏例如(非静态)方法的东西。在这里,它是一个阴影的例子。在大多数地方,强制转换A只是有助于解决歧义(例如c.m(),原样可以同时引用A#mC#m[无法从a] 访问),否则会导致编译错误。

还是尽管打破了继承链,但还是会被D.m()覆盖?A.m()B.m()C.m()

b.m()是一个模棱两可的电话,因为如果您将可见性因素放在一边,两者都适用A#mB#m也是如此c.m()((A)b).m()((A)c).m()清楚地指出A#m调用者可以访问哪个。

((A)d).m()更有趣的是:两者AD都驻留在同一个包中(因此,可访问[与上述两种情况不同])并D间接继承A. 在动态调度期间,Java 将能够调用D#m,因为D#m实际上覆盖A#m并且没有理由不调用它(尽管继承路径上的混乱[请记住,由于可见性问题,既不B#m也不C#m覆盖])。A#m

更糟糕的是,下面的代码显示了覆盖效果,为什么?

我无法解释这一点,因为这不是我所期望的行为。

我敢说结果

((A)e).m();
((A)f).m();

应该与结果相同

((D)e).m();
((D)f).m();

这是

D
D

因为无法bc.a


推荐阅读