Oracle Java教程-静态类-教程中可能存在错误



我是Java新手,从Oracle Java教程中学习Java。我现在正在学习嵌套类、静态类和内部类。我发现下面的解释似乎很奇怪,我认为这是错误的。

发件人:https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

嵌套类是其封闭类的成员。非静态嵌套类(内部类)可以访问封闭类的其他成员,即使它们被声明为私有的静态嵌套类不能访问封闭类的其他成员

最后一句"静态嵌套类不能访问封闭类的其他成员"很奇怪,但可能指的是实例成员,说静态类就像一个静态方法,不能访问实例变量。但下一个注释更奇怪:

注意:静态嵌套类与其外部类(和其他类)的实例成员进行交互,就像任何其他顶级类一样。实际上,静态嵌套类在行为上是一个顶级类,为了封装方便,它已经嵌套在另一个顶层类中。

这似乎很奇怪,因为这意味着静态类不能访问外部类的私有实例成员。我已经编写了以下代码,这些代码编译并运行,并演示了静态类可以访问外部实例私有变量。

public class A {
private int x;
static private int y;

static public class B{
static void doSomething(){
y++;
System.out.println("y is now " + y );
}
static void doSomethingElse(A a)
{
a.x++;
System.out.println("a.x is " + a.x );
}
}
}
// ------
public class Main {
public static void main(String[] args){
A a = new A();
A.B b = new A.B();
b.doSomething();
b.doSomethingElse(a);
}
}

这是教程中的一个错误,还是我可能没有很好地理解一些东西?感谢

这是教程中的一个错误,还是我对某些内容理解不好?

您理解错误,教程是正确的。在嵌套的静态类中,没有任何地方可以直接操作外部类的实例字段。我说的是这些没有附加实例的字段——没有任何地方可以直接操作x而不将其附加到A实例。

所以你可以这样做:

static void doSomethingElse(A a) {
a.x++;  // x is part of the A instance passed into a parameter
System.out.println("a.x is " + a.x );
}

但你不能这样做:

static void doSomethingElse2() {
x++;
System.out.println("x is " + x );
}

如果B是静态嵌套的或独立的非嵌套类,则此代码将是相同的。


你问:

"静态嵌套类与外部类的实例成员交互,就像任何其他顶级类一样"?

正如上面所示——非静态嵌套类可以直接与a字段交互(如doSomethingElse2()所示),而不需要支持A实例,而静态嵌套类和独立类都不能。它们都需要单独的A实例,在这里它被传递到doSomethingElse(A a)方法参数中。


静态嵌套类和独立类之间的主要区别在于,前者嵌套类可以访问外部类的私有成员,而独立类则不能。也许这就是你困惑的根源。

这是教程中的一个错误,还是我可能没有很好地理解一些东西?

你完全理解。教程页面充其量是误导性的。

这里有两个独立的概念:

  1. 您是否有权访问Java访问控制规则范围内的东西(例如,private、package private、protected、public)。

  2. "静态"的含义"内部"嵌套类的实例总是与封闭类的实例相关联(将对封闭类实例的引用存储在内部类的隐藏实例字段中)。"静态"嵌套类没有这个。

教程页面混淆了这两个概念。

嵌套类是其封闭类的成员

是的。

非静态嵌套类(内部类)可以访问封闭类的其他成员,即使它们被声明为私有静态嵌套类不能访问封闭类的其他成员

没有。

通过自己提供实例,您可以看到静态类确实可以访问封装类的成员,包括私有实例字段,因此示例中的a.x++;会编译。这就是访问。

通过使用"访问"one_answers"私有"这两个词,该段强烈暗示它在Java语言规范中给出的定义中谈论访问控制但事实并非如此它只是试图解释概念#2,关于封闭类的实例如何与嵌套类相关联。即便如此,这仍然是错误的,因为静态嵌套类当然可以访问封闭类的静态成员,而段落中说他们不能访问。写那一页的人太草率了。

注意:静态嵌套类与其外部类(和其他类)的实例成员进行交互就像任何其他顶级类一样实际上,静态嵌套类在行为上是一个顶级类,为了封装方便,它已经嵌套在另一个顶层类中

这段话仍然在谈论静态的含义。它并没有试图对访问控制发表任何言论,尽管它有可能被误解。


以下是JLS§6.6.1给出的正确访问控制规则——确定可访问性:

[If]成员或构造函数被声明为private,当且仅当它发生在包含成员或构造函数声明的顶级类(§7.6)的主体内时,才允许[..]访问。

这个定义非常短,但它涵盖了这里的所有相关内容。

这意味着所有嵌套类(因为它们"在顶级类的主体内")都可以访问封闭类的所有成员和构造函数,而不管嵌套类是静态的还是实例的,也不管访问的东西是静态的或实例的。

此外,所有嵌套类还可以访问同一顶级类中所有其他嵌套类的所有成员和构造函数。

顶层类可以访问嵌套在其中的所有类的所有成员和构造函数

我引用的JLS的句子指的是private访问。但是,如果成员或构造函数不是private,那么它的访问级别只能更宽松,至少是包访问,并且包含在同一顶级类型中的类也不可避免地在同一个包中,因此即使没有特殊处理,它们也可以相互访问。

基本上,顶级(非封闭)类及其内部的所有内容构成了嵌套。原则上,这个巢穴中的一切都可以访问其中的其他一切。如果它是实例成员,您还需要以某种方式首先获得一个实例,但这总是正确的。

最新更新