方法本地内部类与内部类

时间:2015-04-14 06:38:16

标签: java inner-classes

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

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

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

6 个答案:

答案 0 :(得分:38)

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

  

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

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

另见JLS §14.3,其中包含类似示例。

答案 1 :(得分:17)

您正在获得输出"中间"因为您拥有代码的顺序。由于方法范围class A在您对new A()的调用后出现,因此您将获得输出" middle"。如果您按如下方式切换订单,您将获得输出" inner":

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

<强>输出:

inner

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

  1. 方法
  2. 有关详细信息,请查看官方Java Language Specification discussing inner classes

答案 2 :(得分:7)

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

  

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

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

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

middle打印而不是outer的原因是内部类A 阴影顶级类A({{ 3}}):

  

名为d的类型的声明n会影响名为n的{​​{1}}范围内的任何其他类型的声明。

这意味着d正文中的任何位置,不合格的MethodLocalVSInner必须引用内部类。

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

A

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

答案 3 :(得分:4)

案例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因为类现在在范围内。

答案 4 :(得分:2)

方法中的

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

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

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

但如果您将方法更改为:

 void go() {

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

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

答案 5 :(得分:1)

您正在使用go

的实例调用MethodLocalVSInner方法

go方法内部 您正在创建A()的实例 这里因为你没有显式地导入外部A class,而直接内部类是在方法调用语句之后,JVM正在选择类inner class A的{​​{1}}并执行go

中的方法