java 为什么内部类可以访问私有方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/663059/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 13:18:13  来源:igfitidea点击:

Why do inner classes make private methods accessible?

javainner-classes

提问by mparaz

I don't understand why this compiles. f() and g() are visible from the inner classes, despite being private. Are they treated special specially because they are inner classes?

我不明白为什么会编译。f() 和 g() 尽管是私有的,但在内部类中是可见的。他们是否因为是内部类而被特殊对待?

If A and B are not static classes, it's still the same.

如果 A 和 B 不是静态类,它仍然是相同的。

class NotPrivate {
    private static class A {
        private void f() {
            new B().g();
        }
    }

    private static class B {
        private void g() {
            new A().f();
        }
    }
}

回答by TofuBeer

(Edit: expanded on the answer to answer some of the comments)

(编辑:扩展答案以回答一些评论)

The compiler takes the inner classes and turns them into top-level classes. Since private methods are only available to the inner class the compiler has to add new "synthetic" methods that have package level access so that the top-level classes have access to it.

编译器获取内部类并将它们转换为顶级类。由于私有方法仅对内部类可用,因此编译器必须添加具有包级别访问权限的新“合成”方法,以便顶级类可以访问它。

Something like this (the $ ones are added by the compiler):

像这样的东西($ 是由编译器添加的):

class A 
{
    private void f() 
    {
        final B b;

        b = new B();

        // call changed by the compiler
        b.$g();
    }

    // method generated by the compiler - visible by classes in the same package
    void $f()
    {
        f();
    }
}

class B
{
    private void g() 
    {
        final A a;

        a = new A();

        // call changed by the compiler
        a.$f();
    }

    // method generated by the compiler - visible by classes in the same package
    void $g()
    {
        g();
    }
}

Non-static classes are the same, but they have the addition of a reference to the outer class so that the methods can be called on it.

非静态类是相同的,但它们添加了对外部类的引用,以便可以在其上调用方法。

The reason Java does it this way is that they did not want to require VM changes to support inner classes, so all of the changes had to be at the compiler level.

Java 这样做的原因是他们不想要求 VM 更改以支持内部类,因此所有更改都必须在编译器级别进行。

The compiler takes the inner class and turns it into a top level class (thus, at the VM level there is no such thing as an inner class). The compiler then also has to generate the new "forwarding" methods. They are made at the package level (not public) to ensure that only classes in the same package can access them. The compiler also updated the method calls to the private methods to the generated "forwarding" methods.

编译器将内部类转换为顶级类(因此,在 VM 级别没有内部类这样的东西)。然后编译器还必须生成新的“转发”方法。它们是在包级别(非公共)创建的,以确保只有同一包中的类才能访问它们。编译器还将对私有方法的方法调用更新为生成的“转发”方法。

You can avoid having the compiler generate the method my declaring the methods as "package" (the absence of public, private, and protected). The downside to that is that any class in the package can call the methods.

您可以避免让编译器生成我将方法声明为“包”的方法(没有公共、私有和受保护的)。这样做的缺点是包中的任何类都可以调用这些方法。

Edit:

编辑:

Yes, you can call the generated (synthetic) method, but DON'T DO THIS!:

是的,您可以调用生成的(合成)方法,但不要这样做!:

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class Main
{
    public static void main(final String[] argv)
        throws Exception
    {
        final Class<?> clazz;

        clazz = Class.forName("NotPrivate$A");        

        for(final Method method : clazz.getDeclaredMethods())
        {
            if(method.isSynthetic())
            {
                final Constructor constructor;
                final Object instance;

                constructor = clazz.getDeclaredConstructor(new Class[0]);
                constructor.setAccessible(true);
                instance = constructor.newInstance();
                method.setAccessible(true);
                method.invoke(null, instance);
            }
        }
    }
}

回答by Eric Petroelje

I think this quotesums it up nicely:

我认为这句话很好地总结了它:

...inner classes can access all members of the declaring class, even private members. In fact, the inner class itself is said to be a member of the class; therefore, following the rules of object-oriented engineering, it should have access to all members of the class.

...内部类可以访问声明类的所有成员,甚至是私有成员。实际上,内部类本身被称为类的成员;因此,遵循面向对象工程的规则,它应该可以访问该类的所有成员。

And following from that, since both inner classes are really just part of the containing class, they should be able to access each others private members as well.

然后,由于两个内部类实际上只是包含类的一部分,因此它们也应该能够访问彼此的私有成员。

回答by Lou Franco

Java compiles in special accessors with $ in them. So you can't write Java that access the private methods. Explained here:

Java 在特殊的访问器中编译,其中包含 $。所以你不能编写访问私有方法的 Java。在这里解释:

http://www.retrologic.com/innerclasses.doc7.html

http://www.retrologic.com/innerclasses.doc7.html

There is one more category of compiler-generated members. A private member m of a class C may be used by another class D, if one class encloses the other, or if they are enclosed by a common class. Since the virtual machine does not know about this sort of grouping, the compiler creates a local protocol of access methods in C to allow D to read, write, or call the member m. These methods have names of the form access$0, access$1, etc. They are never public. Access methods are unique in that they may be added to enclosing classes, not just inner classes.

还有一类编译器生成的成员。如果一个类包含另一个类,或者如果它们被一个公共类包含,则类 C 的私有成员 m 可以被另一个类 D 使用。由于虚拟机不知道这种分组,编译器在 C 中创建了访问方法的本地协议,以允许 D 读取、写入或调用成员 m。这些方法的名称形式为 access$0、access$1 等。它们从不公开。访问方法的独特之处在于它们可以添加到封闭类中,而不仅仅是内部类。

回答by EternalBeginner

As User 'A Dude' explained it in the comments of the accepted answer:

正如用户“A Dude”在已接受答案的评论中所解释的那样:

It compiles, because it is required to be working in that way by the language specifation, ie. the Java Lang Spec says so:

它可以编译,因为语言规范要求它以这种方式工作,即。Java 语言规范是这样说的:

6.6.1 确定可访问性(至少从 JLS6 开始)

"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 节)的主体内时,才允许访问。”

I.e. the "access-scope" of a private member is: everywhere within the lexical boundaries of the top-level class body.

即私有成员的“访问范围”是:在顶级类主体的词法边界内的任何地方。

That means: all private members that are defined within the class-body of the outermost class can be accessed from everywhere else in this class-body.

这意味着:在最外层类的类体内定义的所有私有成员都可以从该类体内的其他任何地方访问。

For instance the private method of an inner class can be accessed from methods of the outer class or from any method of another inner class of the outer class.

例如,可以从外部类的方法或外部类的另一个内部类的任何方法访问内部类的私有方法。