在方法签名中公开声明包私有类型

Luk*_*der 9 java compiler-construction syntax package-private

这在Java中是可能的:

package x;

public class X {

    // How can this method be public??
    public Y getY() {
        return new Y();
    }
}

class Y {}
Run Code Online (Sandbox Code Playgroud)

那么Java编译器允许我将该getY()方法声明为什么是一个很好的理由public?困扰我的是:类Y是包私有的,但访问者getY()在方法签名中声明它.但是在x包之外,我只能将方法的结果分配给Object:

// OK
Object o = new X().getY();

// Not OK:
Y y = new X().getY();
Run Code Online (Sandbox Code Playgroud)

好.现在我可以试着用一个例子来构建一个例子,可以用方法结果协方差来解释.但为了让事情变得更糟,我也可以这样做:

package x;

public class X {
    public Y getY(Y result) {
        return result;
    }
}

class Y {}
Run Code Online (Sandbox Code Playgroud)

现在我永远无法getY(Y result)x包裹外面打电话.我为什么这样做?为什么编译器让我以一种我无法调用它的方式声明一个方法?

Wou*_*rts 6

Java的设计已经有很多想法,但有时候一些次优设计才会滑落.着名的Java Puzzlers清楚地证明了这一点.

另一个包仍然可以使用package-private参数调用该方法.最简单的方法就是通过它null.但这不是因为你仍然可以称之为,这样的结构确实有意义.它破坏了package-private背后的基本思想:只有包本身应该看到它.大多数人会同意任何使用这种结构的代码至少令人困惑,只是有一种难闻的气味.最好不要允许它.

就像旁注一样,它允许的事实会打开更多的角落案例.例如,从执行Arrays.asList(new X().getY())编译的不同包中,但在执行时抛出IllegalAccessError,因为它尝试创建不可访问的Y类的数组.这只是表明这种无法访问的类型的泄漏不符合语言设计其余部分所做的假设.

但是,与Java中的其他不寻常的规则一样,它在Java的第一个版本中被允许.因为它并不是什么大问题,并且因为向后兼容性对Java来说更重要,所以改善这种情况(不允许它)根本就不值得了.