2016-10-11 106 views
10

我今天正在嘗試匿名類。當我做System.out.println(super.x);,它打印12,當我用System.out.println(x);它打印4.我認爲super.x將打印4,並想知道是否有人可以請向我解釋爲什麼這是?匿名類變量

public class AnonClass { 

    private int x = 1; 

    public AnonClass(int x) { 
     this.x = x; 
    } 

    public static void main(String[] args) { 
     AnonClass test = new AnonClass(4); 
     test.testMethod(); 
    } 

    public void testMethod() { 

     AnonClass anon = new AnonClass(12) { 
      { 
       System.out.println(super.x); //Prints 12 
       System.out.println(x); //prints 4 
      } 
     }; 

    } 
} 
+0

我想'super'只與繼承使用。我猜不會。 – Gendarme

+2

@Gendarme你爲什麼猜這個?匿名類繼承它們擴展的類。 –

+0

@AndyTurner嗯,我想我在Java中的知識太淺了。這整個事情超越了我。 – Gendarme

回答

11

當你定義內class AnonClass匿名類是這樣的:

AnonClass anon = 
    new AnonClass(12) { 
     { 
     System.out.println(super.x); //Prints 12 
     System.out.println(x); //prints 4 
     } 
    }; 

,編譯器會創建一個類是這樣的:

class AnonClass$1 extends AnonClass { 
    final AnonClass enclosed; 

    AnonClass$1(AnonClass enclosed, int x) { 
    super(x); 
    System.out.println(super.x); 
    System.out.println(enclosed.x); 
    this.enclosed = enclosed; 
    } 
} 

,然後調用它像:

AnonClass anon = new AnonClass$1(this, 12); 

請注意,superconstructor(super(x);)的調用發生在實例初始化程序(System.out.println行)的內容之前。

因此,字段AnonClass.x由superconstructor初始化爲12,然後通過System.out.println(super.x);將其值打印爲12

然後,System.out.println(x)實際上是在AnonClass封閉情況下,它的值是4

它不會再次打印12的原因是,xprivate引用x;正如它在JLS Sec 8.2中所述:

聲明爲private的類的成員不會被該類的子類繼承。

所以沒有AnonClass$1.x打印;在範圍內稱爲x的唯一標識符是AnonClass.x

+1

java規範的哪個部分說,匿名類中的非限定標識符解析爲封閉類而不是匿名超類?我會期待一個「模糊」的編譯錯誤。 – Andreas

+0

這確實是一個有趣的問題 - 還有一個不使用雙括號初始化的理由。將讚賞在實例初始化程序中引用JLS有關可變分辨率的內容。 –

+2

下面是一個提示,回答我的問題,我猜:如果從字段'x'中刪除'private','super.x'和'x'都指向超級實例。只有當'x'是'private'時,不合格的'x'纔會指向封閉的實例。 – Andreas

1

你這裏有兩類:普通類AnonClass和匿名類AnonClass$1延伸AnonClass

這兩個類有x

你也有兩個對象:實例化AnonClass類型的一個內部mainx = 4和第二種AnonClass$1內部示例testMethod()x = 12

當您打印super.x的值時,您正在訪問第二個對象的x字段;但x值屬於第一對象,因爲你的類不static,幷包含對外部類的實例

參考的隱式引用:Nested Classes in Java