我是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);
}
}
这是本教程中的错误,还是我不太了解? 谢谢
答案 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)
这是本教程中的错误,还是我不太了解?
您的理解很好。教程页面充其量是一种误导。
这里有两个独立的概念:
您是否有权访问Java 访问控制规则内的内容(例如,私有,程序包私有,受保护,公共)。
“静态”的含义。嵌套类的“内部”实例始终与封闭类的实例相关联(将对封闭类实例的引用存储在内部类的隐藏实例字段)。 “静态”嵌套类没有该类。
教程页面混淆了这两种概念。
嵌套类是其封闭类的成员。
是的
非静态嵌套类(内部类)可以访问封闭类的其他成员,即使它们被声明为私有的也是如此。 静态嵌套类无权访问该封闭类的其他成员。
不。
通过自己提供实例,您会看到静态类确实具有对封闭类成员(包括私有实例字段)的访问,因此,为什么您的示例中的a.x++;
可以编译。这就是访问权限。
通过使用“访问”和“专用”一词,该段落强烈暗示它是在Java语言规范给出的定义内谈论访问控制。 但是不是。它只是试图解释概念#2,即封闭类的实例如何与嵌套类相关联。即便如此,这仍然是错误的,因为静态嵌套类当然可以访问封闭类的 static 成员,而该段落却没有。写那个页面的人马虎。
注意:静态嵌套类与其外部类的实例成员进行交互(和其他类),就像其他任何顶级类一样。实际上,静态嵌套类在行为上是顶级类,为了包装方便,该顶级类已嵌套在另一个顶级类中。
本段仍在讨论静态的含义。尽管它有可能被误解,但它并没有试图说出任何有关访问控制的信息。
这是JLS§6.6.1 – Determining Accessibility给出的正确访问控制规则:
[如果]将该成员或构造函数声明为
private
,则当且仅当它在包含该声明的顶级类(§7.6)的主体内发生时,才允许[..]访问。成员或构造函数。
这个定义很短,但是涵盖了这里所有相关的内容。
这意味着所有嵌套类(因为它们“在顶级类的主体内”)可以访问封闭类的所有成员和构造函数,而不管嵌套类是否是静态或实例,并且无论所访问的对象是静态还是实例。
此外,所有嵌套类还可以访问同一顶级类中所有 other 嵌套类的所有成员和构造函数。
顶级类可以访问嵌套在其中的所有类的所有成员和构造函数。
我引用的JLS语句涉及private
访问。但是,如果成员或构造函数不是private
,则其访问级别只能是更宽松的,至少是程序包访问,并且包含在同一顶级类型中的类也不可避免地也在同一程序包中,因此它们将即使没有特殊待遇也可以彼此访问。
基本上,顶级(非封闭式)类及其中的所有内容均构成巢。原则上,该嵌套中的所有内容都可以访问其中的其他所有内容。如果它是实例成员,则还需要首先以某种方式获取实例,但这始终是正确的。