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

时间:2021-07-13 22:59:34

I observed that Outer classes can access inner classes private instance variables. How is this possible? Here is a sample code demonstrating the same:

我发现外部类可以访问内部类私有实例变量。这怎么可能?下面是演示相同代码的示例代码:

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

Why is this behavior allowed?

为什么允许这种行为?

10 个解决方案

#1


75  

The inner class is just a way to cleanly separate some functionality that really belongs to the original outer class. They are intended to be used when you have 2 requirements:

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

  1. Some piece of functionality in your outer class would be most clear if it was implemented in a separate class.
  2. 如果是在一个单独的类中实现的,那么外层类中的某些功能将是最清晰的。
  3. Even though it's in a separate class, the functionality is very closely tied to way that the outer class works.
  4. 即使它是在一个单独的类中,功能仍然与外部类的工作方式紧密相关。

Given these requirements, inner classes have full access to their outer class. Since they're basically a member of the outer class, it makes sense that they have access to methods and attributes of the outer class -- including privates.

考虑到这些需求,内部类可以完全访问它们的外部类。因为它们基本上是外部类的成员,所以它们可以访问外部类的方法和属性——包括私有类。

#2


48  

The inner class is (for purposes of access control) considered to be part of the containing class. This means full access to all privates.

内部类(为了访问控制的目的)被认为是包含类的一部分。这意味着可以进入所有的私人领地。

The way this is implemented is using synthetic package-protected methods: The inner class will be compiled to a separate class in the same package (ABC$XYZ). The JVM does not support this level of isolation directly, so that at the bytecode-level ABC$XYZ will have package-protected methods that the outer class uses to get to the private methods/fields.

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

#3


48  

If you like to hide the private members of your inner class, you may define an Interface with the public members and create an anonymous inner class that implements this interface. Example bellow:

如果希望隐藏内部类的私有成员,可以定义与公共成员的接口,并创建实现该接口的匿名内部类。示例波形:

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

#4


12  

There's a correct answer appearing on another question similar to this: Why can the private member of an nested class be accessed by the methods of the enclosing class?

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

It says there's a definition of private scoping on JLS - Determining Accessibility:

它说在JLS上有一个私有范围的定义——决定可访问性:

Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.

否则,如果成员或构造函数声明私有,那么访问允许当且仅当它发生在身体的*类(§7.6)包含成员或声明的构造函数。

#5


4  

An IMHO important use case for inner classes is the factory pattern. The enclosing class may prepare an instance of the inner class w/o access restrictions and pass the instance to the outside world, where private access will be honored.

内部类的一个重要用例是工厂模式。封闭类可以准备一个内部类w/o访问限制的实例,并将实例传递给外部世界,在那里将获得私有访问权。

In contradiction to abyx declaring the class static doesn't change access restrictions to the enclosing class, as shown below. Also the access restrictions between static classes in the same enclosing class are working. I was surprised ...

与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);
    }
}

#6


3  

Access restrictions are done on a per class basis. There is no way for a method declared in a class to not be able to access all of the instance/class members. It this stands to reason that inner classes also have unfettered access to the members of the outer class, and the outer class has unfettered access to the members of the inner class.

访问限制是在每个类的基础上完成的。类中声明的方法无法访问所有实例/类成员。由此可见,内部阶级也可以不受约束地接触到外部阶级的成员,而外部阶级也可以不受约束地接触到内部阶级的成员。

By putting a class inside another class you are making it tightly tied to the implementation, and anything that is part of the implementation should have access to the other parts.

通过将一个类放入另一个类中,您将使它与实现紧密地绑定在一起,而任何属于实现的部分都应该可以访问其他部分。

#7


3  

The logic behind inner classes is that if you create an inner class in an outer class, that's because they will need to share a few things, and thus it makes sense for them to be able to have more flexibility than "regular" classes have.

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

If, in your case, it makes no sense for the classes to be able to see each other's inner workings - which basically means that the inner class could simply have been made a regular class, you can declare the inner class as static class XYZ. Using static will mean they will not share state (and, for example new ABC().new XYZ() won't work, and you will need to use new ABC.XYZ().
But, if that's the case, you should think about whether XYZ should really be an inner class and that maybe it deserves its own file. Sometimes it makes sense to create a static inner class (for example, if you need a small class that implements an interface your outer class is using, and that won't be helpful anywhere else). But at about half of the time it should have been made an outer class.

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

#8


1  

Thilo added a good answer for your first question "How is this possible?". I wish to elaborate a bit on the second asked question: Why is this behavior allowed?

第一个问题“这怎么可能?”我想详细阐述第二个问题:为什么允许这种行为?

For starters, let's just be perfectly clear that this behavior is not only allowed for inner classes which by definition is non-static nested types. This behavior is allowed for all nested types, including nested enums and interfaces which must be static and cannot have an enclosing instance. Basically, the model is a simplification down to the following statement: Nested code have full access to enclosing code - and vice versa.

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

So, why then? I think an example illustrate the point better.

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

Think of your body and your brain. If you inject heroin into your arm, your brain gets high. If the amygdala region of your brain see what he believe is a threat to your personally safety, say a wasp for example, he'll make your body turn the other way around and run for the hills without You "thinking" twice about it.

想想你的身体和你的大脑。如果你往手臂里注射海洛因,你的大脑就会兴奋起来。如果你大脑的扁桃体区域看到他认为是对你个人安全的威胁,比如黄蜂,他会让你的身体转向另一边,在你没有“考虑”两次的情况下跑向山丘。

So, the brain is an intrinsic part of the body - and strangely enough, the other way around too. Using access control between such closely related entities forfeit their claim of relationship. If you do need access control, then you need to separate the classes more into truly distinct units. Until then, they are the same unit. A driving example for further studies would be to look at how a Java Iterator usually is implemented.

因此,大脑是身体固有的一部分——奇怪的是,反过来也是如此。使用这些密切相关的实体之间的访问控制,就丧失了它们之间的关系。如果您确实需要访问控制,那么您需要将类更多地分离到真正不同的单元中。在那之前,它们是同一个单位。进一步研究的一个驱动示例是研究Java迭代器通常是如何实现的。

Unlimited access from enclosing code to nested code makes it, for the most part, rather useless to add access modifiers to fields and methods of a nested type. Doing so is adding clutter and might provide a false sense of safety for new comers of the Java programming language.

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

#9


-1  

Inner class is regarded as an attribute of the Outer class. Therefore, no matter the Inner class instance variable is private or not, Outer class can access without any problem just like accessing its other private attributes(variables).

内部类被认为是外部类的属性。因此,无论内部类实例变量是否为private,外部类都可以不受任何问题的访问,就像访问它的其他私有属性(变量)一样。

class Outer{

private int a;

class Inner{
private int b=0;
}

void outMethod(){
a = new Inner().b;
}
}

#10


-2  

Because your main() method is in the ABC class, which can access its own inner class.

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

#1


75  

The inner class is just a way to cleanly separate some functionality that really belongs to the original outer class. They are intended to be used when you have 2 requirements:

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

  1. Some piece of functionality in your outer class would be most clear if it was implemented in a separate class.
  2. 如果是在一个单独的类中实现的,那么外层类中的某些功能将是最清晰的。
  3. Even though it's in a separate class, the functionality is very closely tied to way that the outer class works.
  4. 即使它是在一个单独的类中,功能仍然与外部类的工作方式紧密相关。

Given these requirements, inner classes have full access to their outer class. Since they're basically a member of the outer class, it makes sense that they have access to methods and attributes of the outer class -- including privates.

考虑到这些需求,内部类可以完全访问它们的外部类。因为它们基本上是外部类的成员,所以它们可以访问外部类的方法和属性——包括私有类。

#2


48  

The inner class is (for purposes of access control) considered to be part of the containing class. This means full access to all privates.

内部类(为了访问控制的目的)被认为是包含类的一部分。这意味着可以进入所有的私人领地。

The way this is implemented is using synthetic package-protected methods: The inner class will be compiled to a separate class in the same package (ABC$XYZ). The JVM does not support this level of isolation directly, so that at the bytecode-level ABC$XYZ will have package-protected methods that the outer class uses to get to the private methods/fields.

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

#3


48  

If you like to hide the private members of your inner class, you may define an Interface with the public members and create an anonymous inner class that implements this interface. Example bellow:

如果希望隐藏内部类的私有成员,可以定义与公共成员的接口,并创建实现该接口的匿名内部类。示例波形:

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

#4


12  

There's a correct answer appearing on another question similar to this: Why can the private member of an nested class be accessed by the methods of the enclosing class?

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

It says there's a definition of private scoping on JLS - Determining Accessibility:

它说在JLS上有一个私有范围的定义——决定可访问性:

Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.

否则,如果成员或构造函数声明私有,那么访问允许当且仅当它发生在身体的*类(§7.6)包含成员或声明的构造函数。

#5


4  

An IMHO important use case for inner classes is the factory pattern. The enclosing class may prepare an instance of the inner class w/o access restrictions and pass the instance to the outside world, where private access will be honored.

内部类的一个重要用例是工厂模式。封闭类可以准备一个内部类w/o访问限制的实例,并将实例传递给外部世界,在那里将获得私有访问权。

In contradiction to abyx declaring the class static doesn't change access restrictions to the enclosing class, as shown below. Also the access restrictions between static classes in the same enclosing class are working. I was surprised ...

与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);
    }
}

#6


3  

Access restrictions are done on a per class basis. There is no way for a method declared in a class to not be able to access all of the instance/class members. It this stands to reason that inner classes also have unfettered access to the members of the outer class, and the outer class has unfettered access to the members of the inner class.

访问限制是在每个类的基础上完成的。类中声明的方法无法访问所有实例/类成员。由此可见,内部阶级也可以不受约束地接触到外部阶级的成员,而外部阶级也可以不受约束地接触到内部阶级的成员。

By putting a class inside another class you are making it tightly tied to the implementation, and anything that is part of the implementation should have access to the other parts.

通过将一个类放入另一个类中,您将使它与实现紧密地绑定在一起,而任何属于实现的部分都应该可以访问其他部分。

#7


3  

The logic behind inner classes is that if you create an inner class in an outer class, that's because they will need to share a few things, and thus it makes sense for them to be able to have more flexibility than "regular" classes have.

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

If, in your case, it makes no sense for the classes to be able to see each other's inner workings - which basically means that the inner class could simply have been made a regular class, you can declare the inner class as static class XYZ. Using static will mean they will not share state (and, for example new ABC().new XYZ() won't work, and you will need to use new ABC.XYZ().
But, if that's the case, you should think about whether XYZ should really be an inner class and that maybe it deserves its own file. Sometimes it makes sense to create a static inner class (for example, if you need a small class that implements an interface your outer class is using, and that won't be helpful anywhere else). But at about half of the time it should have been made an outer class.

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

#8


1  

Thilo added a good answer for your first question "How is this possible?". I wish to elaborate a bit on the second asked question: Why is this behavior allowed?

第一个问题“这怎么可能?”我想详细阐述第二个问题:为什么允许这种行为?

For starters, let's just be perfectly clear that this behavior is not only allowed for inner classes which by definition is non-static nested types. This behavior is allowed for all nested types, including nested enums and interfaces which must be static and cannot have an enclosing instance. Basically, the model is a simplification down to the following statement: Nested code have full access to enclosing code - and vice versa.

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

So, why then? I think an example illustrate the point better.

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

Think of your body and your brain. If you inject heroin into your arm, your brain gets high. If the amygdala region of your brain see what he believe is a threat to your personally safety, say a wasp for example, he'll make your body turn the other way around and run for the hills without You "thinking" twice about it.

想想你的身体和你的大脑。如果你往手臂里注射海洛因,你的大脑就会兴奋起来。如果你大脑的扁桃体区域看到他认为是对你个人安全的威胁,比如黄蜂,他会让你的身体转向另一边,在你没有“考虑”两次的情况下跑向山丘。

So, the brain is an intrinsic part of the body - and strangely enough, the other way around too. Using access control between such closely related entities forfeit their claim of relationship. If you do need access control, then you need to separate the classes more into truly distinct units. Until then, they are the same unit. A driving example for further studies would be to look at how a Java Iterator usually is implemented.

因此,大脑是身体固有的一部分——奇怪的是,反过来也是如此。使用这些密切相关的实体之间的访问控制,就丧失了它们之间的关系。如果您确实需要访问控制,那么您需要将类更多地分离到真正不同的单元中。在那之前,它们是同一个单位。进一步研究的一个驱动示例是研究Java迭代器通常是如何实现的。

Unlimited access from enclosing code to nested code makes it, for the most part, rather useless to add access modifiers to fields and methods of a nested type. Doing so is adding clutter and might provide a false sense of safety for new comers of the Java programming language.

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

#9


-1  

Inner class is regarded as an attribute of the Outer class. Therefore, no matter the Inner class instance variable is private or not, Outer class can access without any problem just like accessing its other private attributes(variables).

内部类被认为是外部类的属性。因此,无论内部类实例变量是否为private,外部类都可以不受任何问题的访问,就像访问它的其他私有属性(变量)一样。

class Outer{

private int a;

class Inner{
private int b=0;
}

void outMethod(){
a = new Inner().b;
}
}

#10


-2  

Because your main() method is in the ABC class, which can access its own inner class.

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