簡體   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