Oracle Java教程-静态类-教程中可能出现的错误

时间:2018-09-02 11:03:33

标签: 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);
    }
}

这是本教程中的错误,还是我不太了解? 谢谢

2 个答案:

答案 0 :(得分:7)

  

这是本教程中的错误,还是我不太了解?

您所理解的是错误,并且教程 是正确的。在嵌套的静态类中没有任何地方可以直接操纵外部类的实例字段。我说的是这些字段,而没有附加实例–您无法在没有附加到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()所示)而无需支持{{ 1}}实例,而静态嵌套类和独立类都不能。它们都需要单独的A实例,在这里将其传递到您的A方法 参数 中。


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

答案 1 :(得分:3)

  

这是本教程中的错误,还是我不太了解?

您的理解很好。教程页面充其量是一种误导。

这里有两个独立的概念:

  1. 您是否有权访问Java 访问控制规则内的内容(例如,私有,程序包私有,受保护,公共)。

  2. “静态”的含义。嵌套类的“内部”实例始终与封闭类的实例相关联(将对封闭类实例的引用存储在内部类的隐藏实例字段)。 “静态”嵌套类没有该类。

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

  

嵌套类是其封闭类的成员。

是的

  

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

不。

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

通过使用“访问”和“专用”一词,该段落强烈暗示它是在Java语言规范给出的定义内谈论访问控制但是不是。它只是试图解释概念#2,即封闭类的实例如何与嵌套类相关联。即便如此,这仍然是错误的,因为静态嵌套类当然可以访问封闭类的 static 成员,而该段落却没有。写那个页面的人马虎。

  

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

本段仍在讨论静态的含义。尽管它有可能被误解,但它并没有试图说出任何有关访问控制的信息。


这是JLS§6.6.1 – Determining Accessibility给出的正确访问控制规则:

  

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

这个定义很短,但是涵盖了这里所有相关的内容。

这意味着所有嵌套类(因为它们“在顶级类的主体内”)可以访问封闭类的所有成员和构造函数,而不管嵌套类是否是静态或实例,并且无论所访问的对象是静态还是实例。

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

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

我引用的JLS语句涉及private访问。但是,如果成员或构造函数不是private,则其访问级别只能是更宽松的,至少是程序包访问,并且包含在同一顶级类型中的类也不可避免地也在同一程序包中,因此它们将即使没有特殊待遇也可以彼此访问。

基本上,顶级(非封闭式)类及其中的所有内容均构成。原则上,该嵌套中的所有内容都可以访问其中的其他所有内容。如果它是实例成员,则还需要首先以某种方式获取实例,但这始终是正确的。