【问题标题】:Inconsistent behaviour of package private access level包私有访问级别的不一致行为
【发布时间】:2014-06-17 22:12:48
【问题描述】:

我知道 package-private(默认)修饰符应该为每个类隐藏一个方法(或成员),但同一个包中的那些除外。但是,我发现此访问级别存在一些问题。

考虑以下代码:

// pack1/MyBaseClass.java
package pack1;

public class MyBaseClass {
    /* package private */ void someMethod() {
        System.out.println("MyBaseClass.someMethod");
    }
}


// pack1/MyDerivedClassFromOtherPackage.java
package pack1;

import pack2.MyDerivedClassInAnotherPackage;

public class MyDerivedClassFromOtherPackage extends MyDerivedClassInAnotherPackage {
    @Override
    /* package private */ void someMethod() {
        System.out.println("MyDerivedClassFromOtherPackage.someMethod");
        // super.someMethod();  // can't compile
    }
}


//pack2/MyDerivedClassInAnotherPackage.java
package pack2;

import pack1.MyBaseClass;

public class MyDerivedClassInAnotherPackage extends MyBaseClass {
    // @Override // can't do this (compile error)
    /* package private */ void someMethod() {
        System.out.println("MyDerivedClassInAnotherPackage.someMethod");
    }
}

所以基本上包 pack1 中有一个带有包私有方法 (MyBaseClass) 的基类。 pack2 中的另一个类(MyDerivedClassInAnotherPackage)扩展了 MyBaseClass,它不能覆盖包私有方法(到目前为止还可以:包私有方法只能在同一个包中访问)。 但是,pack1 中的另一个类扩展了 pack2.MyDerivedClassInAnotherPackage,这一次它可以覆盖它的包私有方法(但它不能调用super.someMethod())。

另一个奇怪的事情是 someMethod 对pack1.MyDerivedClassFromOtherPackage 表现出多态性,但对pack2.MyDerivedClassInAnotherPackage 却不是。下面的代码应该清楚我的意思:

package pack1;

import pack2.MyDerivedClassInAnotherPackage;

public class MainClass {

    public static void main(String[] args) {
        MyBaseClass bc = new MyBaseClass();
        bc.someMethod();
        System.out.println("-------------------------------------------------");

        MyBaseClass otherpack = new MyDerivedClassInAnotherPackage();
        otherpack.someMethod();
        System.out.println("-------------------------------------------------");

        MyBaseClass samepack = new MyDerivedClassFromOtherPackage();
        samepack.someMethod();
        System.out.println("-------------------------------------------------");

    }

}

输出:

MyBaseClass.someMethod
-------------------------------------------------
MyBaseClass.someMethod
-------------------------------------------------
MyDerivedClassFromOtherPackage.someMethod
-------------------------------------------------

与这些行为相关的问题:

1. How come that pack1.MyDerivedClassFromOtherPackage is allowed to override the (package-private) method of pack2.MyDerivedClassInAnotherPackage?
2. In spite of this, why is it not possible to call super.someMethod() from pack1.MyDerivedClassFromOtherPackage?
3. Why is the class in the same package (pack1) behaving polymorphically and the one in the other package (pack2) not?

PS1.:我知道我应该一次在 SO 上发布一个问题,但我觉得这三个问题在某种程度上必须具有相同的根本原因。 (我怀疑实际上 pack1.MyDerivedClassFromOtherPackage.someFunction 覆盖了 pack1.MyBaseClass.someFunction 而不是 pack2.MyDerivedClassInAnotherPackage.someFunction。但这仍然不能解释第二个问题,而且我无法确认。)

PS2.:对于这种情况,我没有任何真正的用例。我只是在玩一些极端案例(为 OCA 考试做准备)。

【问题讨论】:

  • 您是否尝试过使用 public 修饰符覆盖 pack2.MyDerivedClassInAnotherPackage 中的 someMethod?
  • @broncoAbierto:我不明白你的建议。如果我这样做,它将如何帮助我理解包私有(默认)访问级别的行为。 (这是问题的目的。)
  • 我的猜测是你不能覆盖,因为通过声明它对 pack2-package 私有的可见性,你限制了它的可访问性。
  • @RKC:感谢您的改进。不过我不明白最后一个:你为什么把我的问题写成代码?
  • @broncoAbierto:好的,但是为什么它让我把覆盖注释放在上面呢? (见第一个问题。)

标签: java


【解决方案1】:

1) 你在这里覆盖的不是 MyDerivedClassInAnotherPackage#someMethod,而是 MyBaseClass#someMethod()。由于包隐私,第一个被跳过,编译器正确地将覆盖的级别解析为 MyBaseClass,因为您的子类与其在同一个包中。

请注意,这是在我们从层次结构中的第二个类中删除 @Override 注释的假设下成立的 - 否则您的代码甚至无法编译。

这里有趣的后续问题是为什么注释系统仍然抛出错误,而代码在这种情况下编译得很好。

2) 因为 super 解析为直接超类,在这种情况下您无法访问其方法。

3) 编辑:正如 BroncoAbiertos 回答中指出的那样,这仅仅是因为这是唯一实际覆盖该方法的地方。实际上,您只能通过从第二个类中删除 @Override 注释来编译它,如上面的答案 1 所示,否则您的代码将无法编译。

【讨论】:

  • 关于第一个答案,我认为它可以编译,因为它根本不会覆盖父方法。然而,如果你添加了 override 注释,你就是在告诉编译器确保你覆盖了某些东西,这就是它不能编译的原因。
  • 没错,但我正在考虑层次结构中第三类中的注释。如果您只保留该注释,并删除第二个注释,则代码会编译,但注释处理器仍会报错。
  • 感谢你们两位的澄清。我认为这两个答案都是正确的,但不幸的是我只能接受一个......
【解决方案2】:
  1. 您不能覆盖 pack2.MyDerivedClassInAnotherPackage 中的 someMethod,因为您将它声明为 pack2 的私有包。也就是说,您正在消除对 pack1 的访问,从而限制了它的可见性,这在覆盖方法时是非法的。当您从 pack1.MyDerivedClassFromOtherPackage 覆盖它时,可见性保持不变,这是合法的。
  2. 您无法调用 super.someMethod(),因为您正在尝试访问 pack2.MyDerivedClassInAnotherPackage.someMethod(),但无法从 pack1 访问 pack2.MyDerivedClassInAnotherPackage 方法。
  3. 嗯,该方法仅在 pack1.MyDerivedClassFromOtherPackage 中被覆盖,所以这并不奇怪。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-09
    • 2016-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 2021-05-03
    相关资源
    最近更新 更多