繁体   English   中英

方法本地内部类与内部类

[英]Method local inner class vs inner class

下面的代码生成输出middle 谁能详细解释这是怎么回事?

是因为class A的“内部”版本的声明是在go()方法中创建class A的实例之后发生的吗?

class A {
    void m() {
        System.out.println("outer");
    }
}

public class MethodLocalVSInner {
    public static void main(String[] args) {
        new MethodLocalVSInner().go();
    }

    void go() {
        new A().m();
        class A {
            void m() {
                System.out.println("inner");
            }
        }
    }

    class A {
        void m() {
            System.out.println("middle");
        }
    }
}

我猜你期望调用本地类方法。 这没有发生,因为你在本地类的范围之外使用new A() 因此,它访问范围中的下一个更接近的候选者,即内部类。 来自JLS§6.3

由块(第14.2节)直接包含的本地类声明的范围是直接封闭块的其余部分,包括它自己的类声明。

因此,方法第一行中的new A()将不会访问其后出现的本地类。 如果在此之前移动类声明,您将获得预期的输出。

另请参阅JLS§14.3 ,其中包含类似示例。

由于您拥有代码的顺序,您将获得输出“中间”。 由于方法范围的class A 您调用new A() 之后发生,因此您将获得输出“middle”。 如果您按如下方式切换订单,您将获得输出“内部”:

void go() {
    class A {
        void m() {
            System.out.println("inner");
        }
    }
    new A().m();
}

输出:

inner

实例化class A的优先顺序,从高到低,是:

  1. 方法

有关更多信息,请查看讨论内部类的官方Java语言规范

inner不打印的原因是( 6.3 ):

由块直接包含的本地类声明的范围是直接封闭块的其余部分,包括它自己的类声明。

(在方法内声明的类称为本地类。)

所以A不能引用本地类,因为表达式new A()在声明之前发生。 换句话说,本地类与局部变量具有相似的范围。

middle打印而不是outer的原因是内部类A 影响顶级类A6.4.1 ):

的声明d命名类型的n阴影任何其他类型的命名的声明n是在范围[...]的d

这意味着MethodLocalVSInner正文中的任何位置,非限定A必须引用内部类。

如果您熟悉成员变量的阴影,例如:

class Example {
    int x;
    void setX(int x) {
        //       ┌ 'x' refers to the local method parameter
        this.x = x;
    }
}

基本上同样的事情是继续进行类声明。

情况1:

void go() {
        new A().m();
        class A {
            void m() {
                System.out.println("inner");
            }
        }
    }

在这种情况下,如果您在本地类的范围之外运行您的方法。 这就是它打印middle

案例2:

void go() {
        class A {
            void m() {
                System.out.println("inner");
            }
        }
        new A().m();
    }

在这种情况下,它将打印inner becase类现在在范围内。

在方法中:

 void go() {
    new A().m();
    class A {
        void m() {
            System.out.println("inner");
        }
    }
}

当方法开始执行时,第一行将执行new A().m();

并且因为内部类已经在范围内,所以将创建该类的对象,并且将为inner class调用m方法而不是local method class因为它仍然不在范围内。 这就是为什么你得到middle作为输出。

但如果您将方法更改为:

 void go() {

    class A {
        void m() {
            System.out.println("inner");
        }
    }
   new A().m();
}

您的本地方法类现在将在范围内并具有更高的首选项,因此您现在将获得输出inner

您正在使用MethodLocalVSInner的实例调用go方法

在go方法中你要创建一个A()实例,因为你没有显式地导入外部A class而直接内部类是在方法调用语句之后,JVM正在选择MethodLocalVSInner类级别的inner class A并在其中执行go方法

暂无
暂无

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

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