Java 方法局部内部类与内部类

Java 方法局部内部类与内部类,java,inner-classes,Java,Inner Classes,下面的代码生成输出middle。有人能详细解释这是怎么发生的吗 是因为class A的“内部”版本声明是在go()方法中创建class A的实例之后进行的吗 class A { void m() { System.out.println("outer"); } } public class MethodLocalVSInner { public static void main(String[] args) { new MethodLoc

下面的代码生成输出
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");
        }
    }
}

我猜您希望调用本地类方法。这并没有发生,因为您使用的
newa()
超出了本地类的范围。因此,它访问范围中下一个更接近的候选对象,即内部类。发件人:

直接由块(§14.2)封闭的局部类声明的范围是直接封闭块的其余部分,包括其自身的类声明

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


另请参见,其中包含类似的示例。

由于代码的顺序,您将获得“中间”输出。由于在调用
newa()
之后发生了作用域为
class A
的方法,因此得到的输出是“中间”。如果按如下顺序切换,您将获得“内部”输出:

输出:

内部

实例化A类的优先顺序从高到低为:

  • 挡块
  • 方法
  • 阶级
  • 包装

  • 有关更多信息,请查看官方网站。

    您正在使用
    MethodLocalVSInner

    内围棋法 您正在创建
    A()
    在这里,由于您没有显式导入外部
    A类
    ,而直接内部类位于方法调用语句之后,因此JVM正在选择
    内部类A
    ,该类位于
    MethodLocalVSInner
    的类级别,并在该类内部执行go方法

    案例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();
        }
    
    在这种情况下,它将打印
    内部
    ,因为类现在在范围内。

    在方法中:

     void go() {
        new A().m();
        class A {
            void m() {
                System.out.println("inner");
            }
        }
    }
    
    当方法开始执行时,将执行第一行
    newa().m()

    因为内部类已经在作用域中,所以将创建该类的对象,并且将为
    内部类
    调用
    m
    方法,而不是为
    本地方法类
    ,因为它仍然不在作用域中。这就是为什么要将
    中间
    作为输出

    但如果您将方法更改为:

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

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

    内部
    无法打印的原因是():

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

    (在方法中声明的类称为局部类。)

    因此
    A
    不能引用本地类,因为表达式
    newa()
    发生在其声明之前。换句话说,局部类的作用域与局部变量相似

    打印中间类而不是外部类的原因是内部类
    A
    将顶层类
    A
    ()隐藏起来:

    名为
    n
    的类型的声明
    d
    隐藏了
    d
    范围[…]内名为
    n
    的任何其他类型的声明

    这意味着
    MethodLocalVSInner
    主体中的任何地方,非限定
    A
    必须引用内部类

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

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

    本质上,类声明也是如此。

    尝试将内部类
    A
    重命名为
    B
    ,您将得到
    外部
    输出。这应该给你一个提示。@TimBiegeleisen我很难选择一个特定的答案,因为你的许多答案都是正确的和切中要害的。你会在eclipse IDE中得到一个警告,类型a从未在本地使用过,也就是说,在方法
    go
    中定义的本地类
    A
    从未被使用过。我很想知道您是为哪个需求实现这个功能的?或者这只是一个棘手的问题@KisHanSarsecHaGajjar在解决一本书中的一些练习,我发现了这个问题。OP也猜到了。但为什么呢?请备份您的答案。然后找到证明它的JLS引用-目前这只是猜测。@Tim Biegeleisen您能告诉我为什么在新的A().m()之前声明类会将其带到范围并打印内部吗?正如@Radiodef在他的答案中指出的,只要您在块中定义本地类
    A
    ,该类的作用域是该定义之后(而不是之前)块的其余部分。至于Java架构师为什么决定这样做,那是另一个问题。@TimBiegeleisen实际上我希望答案中包括这一点。因为这是我想知道的。这与类加载无关。第二次执行该方法时,即使本地类a已加载,它仍将生成相同的输出。这也是由于作用域首选项的缘故。这就像方法,然后是类@ErwinBolwidt我现在已经更改了它。@Radiodef好吧,缺少什么?@RohitJain你能告诉我为什么在
    new A().m()之前声明这个类吗
    将其带到作用域,并打印出
    内部
    @kissarsechagajjar为什么要写这么多感叹号?@Ramswaroop您的问题的答案可能只是Java架构师选择了本地类以这种方式运行。@Ramswaroop我想我引用的JLS部分,关于作用域解释
    class Example {
        int x;
        void setX(int x) {
            //       ┌ 'x' refers to the local method parameter
            this.x = x;
        }
    }