Har*_*ish 169 java private class inner-classes private-members
我观察到外类可以访问内部类私有实例变量.这怎么可能?以下是演示相同内容的示例代码:
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??
}
}
Run Code Online (Sandbox Code Playgroud)
为什么允许这种行为?
Kal*_*see 79
内部类只是一种干净地分离一些真正属于原始外部类的功能的方法.它们适用于有2个要求的情况:
鉴于这些要求,内部类可以完全访问其外部类.因为它们基本上是外部类的成员,所以它们可以访问外部类的方法和属性 - 包括私有类.
小智 60
如果您想隐藏内部类的私有成员,可以使用公共成员定义一个接口,并创建一个实现此接口的匿名内部类.示例:
class ABC{
private interface MyInterface{
void printInt();
}
private static 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
}
}
Run Code Online (Sandbox Code Playgroud)
Thi*_*ilo 52
内部类(为了访问控制的目的)被认为是包含类的一部分.这意味着可以完全访问所有私人.
实现它的方法是使用合成的包保护方法:内部类将被编译到同一个包中的单独类(ABC $ XYZ).JVM不直接支持这种级别的隔离,因此在字节码级ABC $ XYZ将具有包受保护的方法,外部类用于访问私有方法/字段.
Col*_* Su 17
在与此类似的另一个问题上出现了正确的答案: 为什么嵌套类的私有成员可以通过封闭类的方法访问?
否则,如果成员或构造函数被声明为private,则当且仅当它发生在包含成员或构造函数声明的顶级类(第7.6节)的主体内时才允许访问.
Thilo为您的第一个问题“这怎么可能?”添加了一个很好的答案。我想详细说明第二个问题:为什么允许这种行为?
首先,让我们完全清楚这种行为不仅限于内部类,根据定义,内部类是非静态嵌套类型。所有嵌套类型都允许此行为,包括嵌套枚举和接口,它们必须是静态的且不能具有封闭实例。基本上,该模型简化为以下语句:嵌套代码可以完全访问封闭代码 - 反之亦然。
那么,为什么?我认为一个例子更好地说明了这一点。
想想你的身体和大脑。如果你将海洛因注射到你的手臂上,你的大脑就会变得亢奋。如果您大脑的杏仁核区域看到他认为对您的人身安全构成威胁的东西,例如黄蜂,他会让您的身体转向相反的方向并跑向山丘,而您无需“三思”。
所以,大脑是身体的一个内在部分——奇怪的是,反过来也是如此。在此类密切相关的实体之间使用访问控制会丧失其关系声明。如果您确实需要访问控制,那么您需要将类更多地分成真正不同的单元。在那之前,它们是同一个单位。进一步研究的一个驱动示例是查看 JavaIterator通常是如何实现的。
从封闭代码到嵌套代码的无限访问使得在大多数情况下向嵌套类型的字段和方法添加访问修饰符是无用的。这样做会增加混乱,并可能为 Java 编程语言的新手提供错误的安全感。
小智 5
内部类的IMHO重要用例是工厂模式.封闭类可以准备一个没有访问限制的内部类的实例,并将实例传递给外部世界,在那里私人访问将被尊重.
与abyx相反,声明类static不会改变对封闭类的访问限制,如下所示.此外,同一封闭类中的静态类之间的访问限制也正常.我很惊讶 ...
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);
}
}
Run Code Online (Sandbox Code Playgroud)