191

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

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??
    }
}

为什么允许这种行为?

4

10 回答 10

83

内部类只是一种干净地分离真正属于原始外部类的一些功能的方法。当您有 2 个要求时,可以使用它们:

  1. 如果外部类中的某些功能在单独的类中实现,它将是最清楚的。
  2. 即使它在一个单独的类中,其功能也与外部类的工作方式密切相关。

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

于 2009-11-26T05:52:13.077 回答
64

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

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
    }
}
于 2012-02-28T08:54:39.557 回答
59

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

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

于 2009-11-26T06:01:18.360 回答
20

另一个类似的问题出现了正确答案: 为什么嵌套类的私有成员可以被封闭类的方法访问?

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

否则,如果成员或构造函数被声明为私有,则当且仅当它发生在包含成员或构造函数声明的顶级类(第 7.6 节)的主体内时,才允许访问。

于 2014-03-28T03:06:02.910 回答
8

Thilo为您的第一个问题“这怎么可能?”添加了一个很好的答案。我想详细说明第二个问题:为什么允许这种行为?

对于初学者,让我们非常清楚的是,这种行为并不局限于内部类,根据定义,内部类是非静态嵌套类型。所有嵌套类型都允许这种行为,包括嵌套枚举和接口,它们必须是静态的并且不能有封闭的实例。基本上,该模型简化为以下语句:嵌套代码可以完全访问封闭代码 - 反之亦然。

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

想想你的身体和大脑。如果你将海洛因注入手臂,你的大脑就会变得兴奋。如果你大脑的杏仁核区域看到他认为对你的人身安全构成威胁的东西,比如一只黄蜂,他会让你的身体反过来跑,你不会“思考”两次。

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

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

于 2014-08-08T11:30:06.640 回答
5

恕我直言,内部类的一个重要用例是工厂模式。封闭类可以准备一个没有访问限制的内部类的实例,并将该实例传递给外部世界,在那里将尊重私有访问。

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);
    }
}
于 2011-11-08T23:18:34.153 回答
3

访问限制是按班级进行的。类中声明的方法无法访问所有实例/类成员。按理说,内部类也可以不受限制地访问外部类的成员,而外部类也可以不受限制地访问内部类的成员。

通过将一个类放在另一个类中,您可以使其与实现紧密相关,并且作为实现的一部分的任何东西都应该可以访问其他部分。

于 2009-11-26T06:27:39.400 回答
3

内部类背后的逻辑是,如果您在外部类中创建内部类,那是因为它们需要共享一些东西,因此它们能够比“常规”类具有更大的灵活性是有意义的。

如果在您的情况下,类能够看到彼此的内部工作是没有意义的 - 这基本上意味着内部类可以简单地成为一个常规类,您可以将内部类声明为static class XYZ. 使用static将意味着它们不会共享状态(并且,例如new ABC().new XYZ()不会工作,您将需要使用new ABC.XYZ()
但是,如果是这种情况,您应该考虑是否XYZ真的应该是一个内部类,也许它应该拥有自己的文件。有时创建一个静态内部类是有意义的(例如,如果您需要一个小类来实现您的外部类正在使用的接口,而这在其他任何地方都没有帮助)。但大约有一半的时间它应该是一个外部类。

于 2009-11-26T06:42:18.140 回答
-1

内部类被视为外部类的一个属性。因此,无论 Inner 类的实例变量是否是私有的,Outer 类都可以毫无问题地访问,就像访问它的其他私有属性(变量)一样。

class Outer{

private int a;

class Inner{
private int b=0;
}

void outMethod(){
a = new Inner().b;
}
}
于 2018-04-25T03:13:13.017 回答
-2

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

于 2009-11-26T05:49:26.017 回答