繁体   English   中英

内部类甚至可以访问外部类的私有成员。这是否侵犯了隐私?

[英]Inner classes can access even the private members of the outer class.. doesn't it violates the privacy?

我的面试官问我关于内部阶级的问题。向他解释了一切之后,他用我的一句话阻止了我-如果内部阶级可以访问外部阶级的私人成员,那这是否侵犯了隐私? 我无法回答。

答案是No因为内部类是外部类的一部分,就像其他变量和方法一样

可以在同一类的所有方法内部访问类的所有private变量/方法。 内部类是一种特殊情况,其中InnerClass的实例只能存在于OuterClass的实例中。 因此,它可以直接访问其封闭实例的方法和字段。

从JVM的角度来看,是的,内部类访问外部类的私有成员会侵犯隐私。

但是,从Java的角度来看,不,它不侵犯隐私。

JVM观点

Java虚拟机规范,第5.4.4节。 访问控制说:

当且仅当以下任一条件为真时,类或接口D才能访问字段或方法R:

  • [...]

  • R是private在D中声明

因此,JVM将只允许private成员从代码在同一个类访问,即嵌套类不能访问private外部类的成员。

Java视角

Java语言规范,第6.6.1 确定可访问性说:

引用类型的成员(类,接口,字段或方法)或类类型的构造函数仅在可访问类型且声明该成员或构造函数允许访问的情况下才可访问:

  • [...]

  • 否则,将成员或构造函数声明为private ,并且仅当且仅当它发生在包含成员或构造函数的声明的顶级类 (第7.6节的主体内时,才允许访问

因此,可以从该顶级类中任何位置的代码访问顶级类和/或嵌套类中的private成员。 由于嵌套类按定义出现在封闭的顶级类的主体内,因此嵌套类中的代码可以访问外部类的private成员。

综合访问

为了解决这种差异,Java编译器创建了隐藏(合成)方法,以允许在紧密相关的类之间(即,顶级类及其所有嵌套类之间)进行“私有”访问。

这是编译器的一个内部技巧,在规范中并未真正记录。 JVMS,第4.7.8 综合属性说:

[...]源代码中未出现的类成员必须使用Synthetic属性进行标记,否则必须设置其ACC_SYNTHETIC标志。 [...]

JDK 1.1中引入了Synthetic属性,以支持嵌套的类和接口。

有关更多信息,请在网络上搜索java synthetic accessor

另请参阅: 综合访问器方法警告

答:没有内部阶级不会损害外部阶级的隐私。

说明:类中定义的所有实例方法都可以访问该类中定义的私有或非私有字段和方法。 这是因为所有实例方法和字段都属于该类的当前对象。 对于任何内部(非静态)类也是如此,它具有对外部类当前对象的隐式引用。 这就是为什么您只能在外部类的对象的帮助下创建内部(非静态)类的对象的原因。 如果在外部类的任何实例方法中创建内部类的对象,则将在外部类的隐式当前对象引用的帮助下创建内部类的对象。

如果您的内部类是静态的,则它没有对外部类当前对象的隐式引用 任何实例字段或方法都属于该类的Object。 因此,静态内部类无法访问任何私有或非私有实例字段或外部类的方法。

您可以显式设置外部容器类对象的引用,然后再访问。 现在,借助此外部类的显式设置引用,您可以访问私有的Field和方法。

因此,现在让我们修改问题,因为为什么带有外部类显式引用的内部静态类可以访问和修改私有方法和字段?

答案与我们做出这种设计的决定有关。 在类范围内定义任何实体的意图是归属 如果缺少归属感 ,则应重新考虑将类设为内部(静态或非静态)的决策。 当我们希望封装实体的子责任时,应该进行内部类的构造。 这使得相关责任仍然具有凝聚力。 Iterator是任何Collection的一部分,因此它是内部类。 在android的Custom Activity类中定义的Custom AsyncTask类通常被制成私有静态(外部类活动的引用很弱)以防止活动泄漏,因为其目的是修改私有字段。

PS:Afer编译器编译代码后会为内部类生成单独的文件,您可以参考链接以了解当将其他类定义为内部类https:// stackoverflow时,一个类可被其他类访问的字段之间的交互是如何发生的.com / a / 24312109/504133 实际上,合成的getter和setter是由编译器注入代码中的,以便嵌套的静态类可以使用它们访问私有字段。 但这仍然是由语言工具完成的后端任务。

答案是否定的 ,因为内部类具有到外部类的内部链接,并且没有外部类的具体实例就不存在内部类。

但是,如果将static添加到内部类声明中,则意味着它没有指向外部类的链接,并且在您自己的文件中声明类时也是如此。

就是这么简单明了。

如果仔细看一下语句#1#2 ,您会发现它们之间的唯一区别是在#1创建了一个(内部类的)额外对象, 其余所有访问方式都完全相同

有没有违规的地方 ,因为你是故意让门通过像某种形式的访问说明符的开放式publicprotected 内部类不会作为(或无法作为)替代方案,因此绝对不会违反

public class AccessPrivateMemberThruInnerClass {

    private int getUniqueId() {
        return 101;
    }
    private class AnInnerClass {
        public int getParentID() {
            return getUniqueId();  // invokes private method inside a public method.
        }
    }
    public int getUniqueIdForce() {
        return getUniqueId();      // invokes private method inside a public method.
    }
    public AnInnerClass getInnerClassObject(){
        return new AnInnerClass();
    }
    public static void main(String[] args) {
        AccessPrivateMemberThruInnerClass obj = new AccessPrivateMemberThruInnerClass();
        System.out.println(obj.getInnerClassObject().getParentID());   // #1
        System.out.println(obj.getUniqueIdForce());   // #2
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM