为什么外部Java类可以访问内部类的私有成员?

我观察到,外部类可以访问内部类的私有实例variables。 这怎么可能? 下面是一个演示相同的示例代码:

class ABC{ class XYZ{ private int x=10; } public static void main(String... args){ ABC.XYZ xx = new ABC().new XYZ(); System.out.println("Hello :: "+xx.x); ///Why is this allowed?? } } 

为什么这种行为是允许的?

内部类只是一种干净地分离真正属于原始外部类的一些function的方法。 当你有两个要求时,它们被使用:

  1. 如果它是在一个单独的类中实现的,那么外部类中的某些function将是最清晰的。
  2. 即使它在一个单独的类中,它的function与外部类的工作方式非常紧密地联系在一起。

考虑到这些要求,内部类可以完全访问外部类。 由于它们基本上是外部类的成员,因此它们有权访问外部类的方法和属性(包括私有)。

内部类(为了访问控制的目的)被认为是包含类的一部分。 这意味着完全访问所有私人。

实现的方式是使用合成的包保护方法:内部类将被编译到同一个包(ABC $ XYZ)中的一个单独的类。 JVM不直接支持这个级别的隔离,所以在字节码级别ABC $ XYZ将有外部类用来访问私有方法/字段的包保护方法。

如果你想隐藏内部类的私有成员,你可以定义一个与公共成员的接口,并创build一个匿名的内部类来实现这个接口。 示例波纹pipe:

 class ABC{ private interface MyInterface{ void printInt(); } private MyInterface mMember = new MyInterface(){ private int x=10; public void printInt(){ System.out.println(String.valueOf(x)); } } public static void main(String... args){ System.out.println("Hello :: "+mMember.x); ///not allowed mMember.printInt(); // allowed } } 

有一个正确的答案出现在另一个类似于这样的问题上: 为什么可以通过封闭类的方法来访问嵌套类的私有成员?

它说JLS上的私有范围定义是一个定义- 确定可访问性 :

否则,如果成员或构造函数被声明为private, 则只有当它出现在包含成员或构造函数的声明的顶级类(§7.6)的主体内时,才允许访问。

内部类的恕我直言重要用例是工厂模式。 封闭类可以准备内部类的实例,不受访问限制,并将实例传递给外部世界,私有访问将被授予。

与abyx声明静态类不会改变对封闭类的访问限制相矛盾,如下所示。 此外,在相同的封闭类中的静态类之间的访问限制正在工作。 我很惊讶 …

 class MyPrivates { static class Inner1 { private int test1 = 2; } static class Inner2 { private int test2 = new Inner1().test1; } public static void main(String[] args) { System.out.println("Inner : "+new Inner2().test2); } } 

访问限制是按照每个class级来完成的。 在类中声明的方法不能访问所有的实例/类成员。 这就意味着内部类也可以不受限制地访问外部类的成员,外部类可以不受限制地访问内部类的成员。

通过在另一个类中放置一个类,可以使它与实现紧密相关,任何属于实现的部分都应该可以访问其他部分。

内部类的逻辑是,如果你在外部类中创build一个内部类,那是因为它们需要共享一些东西,因此它们比“常规”类具有更多的灵活性是有意义的。

如果在你的情况下,类能够看到彼此的内部工作是没有意义的 – 这基本上意味着内部类可以简单地做成一个普通类,你可以将内部类声明为static class XYZ 。 使用static将意味着他们不会共享状态(例如, new ABC().new XYZ()将不起作用,您将需要使用new ABC.XYZ()
但是,如果是这样的话,你应该考虑XYZ是否真的应该是一个内部类,也许它应该是自己的文件。 有时候创build一个静态的内部类是有意义的(例如,如果你需要一个实现了外部类正在使用的接口的小类,那么在其他地方是没有用的)。 但大约有一半的时候,它应该成为一个外部阶级。

Thilo为你的第一个问题“这怎么可能?”增加了一个很好的答案 。 我想对第二个问题进行详细阐述:为什么允许这种行为?

对于初学者来说,让我们完全清楚的是,这种行为不仅适用于定义为非静态嵌套types的内部类。 所有嵌套types都允许这种行为,包括嵌套的枚举和接口,它们必须是静态的,不能有封闭的实例。 基本上,这个模型简单到下面的语句:嵌套代码可以完全访问封闭代码 – 反之亦然。

那么,为什么呢? 我认为一个例子更好地说明了这一点。

想想你的身体和你的大脑。 如果你把海洛因注入你的arm,你的大脑会变得很高。 如果你的大脑的杏仁核区域看到他认为是对你个人安全的威胁,比如说一个黄蜂,他会让你的身体转向另一个方向奔跑,而你却没有“思考”两次。

所以,大脑是身体的内在组成部分 – 奇怪的是,反过来也是如此。 在这些密切相关的实体之间使用访问控制会丧失他们关系的主张。 如果您确实需要访问控制,那么您需要将这些类更多地分成真正独特的单元。 在此之前,他们是同一个单位。 进一步研究的一个动力的例子是研究Java Iterator通常如何实现。

从封装代码到嵌套代码的无限制访问使得它在大多数情况下无法将访问修饰符添加到嵌套types的字段和方法中。 这样做会增加混乱,并可能为Java编程语言的新来者提供一种错误的安全感。

因为你的main()方法在ABC类中, 可以访问它自己的内部类。