包私有访问级别的行为不一致

时间:2014-05-01 12:23:39

标签: java

我知道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中有一个基类,包含一个package-private方法(MyBaseClass)。 pack2中的另一个类(MyDerivedClassInAnotherPackage)扩展了MyBaseClass,它不能覆盖package-private方法(到目前为止ok:package-private方法只能在同一个包中访问)。 但是,pack1中的另一个类扩展了pack2.MyDerivedClassInAnotherPackage,这次它可以覆盖它的package-private方法(但它不能调用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考试做准备)。

2 个答案:

答案 0 :(得分:0)

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

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

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

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

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

答案 1 :(得分:0)

  1. 您无法覆盖pack2.MyDerivedClassInAnotherPackage中的someMethod,因为您要将其声明包私有到pack2。也就是说,您正在取消pack1的访问权限,从而限制了其可见性,这在覆盖方法时是非法的。当您从pack1.MyDerivedClassFromOtherPackage覆盖它时,可见性保持不变,这是合法的。
  2. 您无法调用super.someMethod(),因为您正在尝试访问pack2.MyDerivedClassInAnotherPackage.someMethod(),但无法从pack1访问pack2.MyDerivedClassInAnotherPackage方法。
  3. 嗯,这个方法只在pack1.MyDerivedClassFromOtherPackage中重写,所以并不奇怪。