讓我們來看看該程序:將出現
public class Outer
{
public Outer() {}
class Inner1 extends Outer
{
public Inner1()
{
super(); // invokes Object() constructor
}
}
class Inner2 extends Inner1
{
public Inner2()
{
super(); // invokes Inner1() constructor
}
}
}
一個錯誤,如果試圖編譯它。
Outer.java:12: cannot reference this before
supertype constructor has been called
super(); // invokes Inner1() constructor
由於Inner2
超本身就是一個內部類,一個不起眼的語言 規則發揮作用。如您所知,內部類的實例化(例如 Inner1
)需要將封閉實例提供給構造函數。通常情況下, 它是隱式提供,但它也可以與以下形式的類的超類 構造函數調用expression.super(args)
如果外圍實例是隱式供給顯式提供,編譯器生成的表達: 它使用對於該參考超類是其中最內層的類。無可否認,這確實很滿意,但這正是編譯器所做的。在這種情況下,超類是Inner1
。因爲當前類, Inner2
,間接擴展Outer,它有Inner1作爲繼承成員。因此, 超類構造函數的限定表達式就是這樣。 編譯器提供了一個封閉的實例,重寫this.super。
默認Inner2
構造函數在調用超類構造函數之前嘗試引用 this
,這是非法的。
蠻力的方式來解決這個問題提供明確合理的 外圍實例:
public class Outer
{
class Inner1 extends Outer { }
class Inner2 extends Inner1
{
public Inner2()
{
Outer.this.super();
}
}
}
這將編譯,但它是複雜的。有一個更好的解決方案: 每當你寫一個成員類,問問自己,這個類真的需要 一個封閉的實例嗎?如果答案是否定的,請將其設爲靜態。內部類有 有時是有用的,但他們可以很容易地引入併發症,使程序 難以理解。它們與泛型,反射和繼承之間存在複雜的相互作用。如果您聲明Inner1
是靜態的,則問題會從 開始。如果您還聲明Inner2
是靜態的,您實際上可以瞭解該程序執行的操作。
總之,一個類既不是內部類又不是另一個類的子類是合適的。更一般地說,擴展一個內部類很少合適;如果你必須的話,請仔細考慮封閉的事例。大多數成員類可以並應該聲明爲靜態的。
據我所知,''this''總是指向你所在類的實例。從內部類實例中訪問父類實例是沒有辦法的(除非你創建一個)。我不太確定你的意思是「隱藏這個」*。 – 2012-04-16 19:56:52
@Lattyware非靜態嵌套類的每個實例都有對其創建它的封閉類的實例的引用。這也是爲什麼你不能在靜態方法中實例化非靜態嵌套類型的原因。在這個例子中,你可以通過以下方式訪問這個封閉的實例:'Outer.this' – 2012-04-16 20:01:06
@stefanbachert你能解釋行爲差異在哪裏嗎? – 2012-04-16 20:02:49