17 回答

TA貢獻(xiàn)1876條經(jīng)驗(yàn) 獲得超7個贊
1)檢查超級是第一個聲明是不足以防止這個問題。例如,你可以把“super(someMethodInSuper());” 在你的構(gòu)造函數(shù)中。這會嘗試在構(gòu)造超類之前訪問它,即使super是第一個語句。(2)編譯器似乎實(shí)現(xiàn)了一個不同的檢查,它本身就足以防止這個問題。消息是“在調(diào)用超類型構(gòu)造函數(shù)之前無法引用xxx”。因此,檢查super是第一個語句是沒有必要的。

TA貢獻(xiàn)1829條經(jīng)驗(yàn) 獲得超4個贊
我通過鏈接構(gòu)造函數(shù)和靜態(tài)方法找到了解決這個問題的方法。我想做的事情看起來像這樣:
public class Foo extends Baz { private final Bar myBar; public Foo(String arg1, String arg2) { // ... // ... Some other stuff needed to construct a 'Bar'... // ... final Bar b = new Bar(arg1, arg2); super(b.baz()): myBar = b; }}
所以基本上構(gòu)造一個基于構(gòu)造函數(shù)參數(shù)的對象,將對象存儲在一個成員中,并將該對象的方法結(jié)果傳遞給super的構(gòu)造函數(shù)。使成員最終也是相當(dāng)重要的,因?yàn)轭惖谋举|(zhì)是它是不可變的。請注意,實(shí)際上,構(gòu)建Bar實(shí)際上需要一些中間對象,因此在我的實(shí)際用例中它不能簡化為單行。
我最終讓它的工作方式如下:
public class Foo extends Baz { private final Bar myBar; private static Bar makeBar(String arg1, String arg2) { // My more complicated setup routine to actually make 'Bar' goes here... return new Bar(arg1, arg2); } public Foo(String arg1, String arg2) { this(makeBar(arg1, arg2)); } private Foo(Bar bar) { super(bar.baz()); myBar = bar; }}
合法代碼,它完成了在調(diào)用超級構(gòu)造函數(shù)之前執(zhí)行多個語句的任務(wù)。

TA貢獻(xiàn)1818條經(jīng)驗(yàn) 獲得超8個贊
因?yàn)镴LS這么說。是否可以以兼容的方式更改JLS以允許它?對。但是,它會使語言規(guī)范變得復(fù)雜,這已經(jīng)非常復(fù)雜了。它不是一個非常有用的東西,它有很多方法(用方法的結(jié)果調(diào)用另一個構(gòu)造函數(shù)this(fn())
- 該方法在另一個構(gòu)造函數(shù)之前調(diào)用,因此也是超級構(gòu)造函數(shù))。因此,進(jìn)行改變的功率重量比是不利的。
編輯2018年3月:在消息記錄:建筑和驗(yàn)證甲骨文是在暗示這個限制被刪除(但不像C#,this
將是絕對未分配的構(gòu)造函數(shù)鏈之前(DU))。
從歷史上看,this()或super()必須是構(gòu)造函數(shù)中的第一個。這種限制從未受到歡迎,并被認(rèn)為是武斷的。有許多微妙的原因,包括驗(yàn)證特殊參與,導(dǎo)致了這種限制。多年來,我們已經(jīng)在虛擬機(jī)層面解決了這些問題,以至于考慮解除這一限制變得切實(shí)可行,不僅僅是記錄,而是所有構(gòu)造函數(shù)。

TA貢獻(xiàn)1810條經(jīng)驗(yàn) 獲得超4個贊
我相當(dāng)肯定(那些熟悉Java規(guī)范的人)會阻止你(a)被允許使用部分構(gòu)造的對象,以及(b)強(qiáng)迫父類的構(gòu)造函數(shù)構(gòu)造為“新的” “對象。
一些“壞”的例子是:
class Thing{ final int x; Thing(int x) { this.x = x; }}class Bad1 extends Thing{ final int z; Bad1(int x, int y) { this.z = this.x + this.y; // WHOOPS! x hasn't been set yet super(x); } }class Bad2 extends Thing{ final int y; Bad2(int x, int y) { this.x = 33; this.y = y; super(x); // WHOOPS! x is supposed to be final } }

TA貢獻(xiàn)1831條經(jīng)驗(yàn) 獲得超10個贊
你問為什么,以及其他答案,imo,并沒有真正說出為什么可以調(diào)用你的超級構(gòu)造函數(shù),但只有它是第一行。原因是你并沒有真正調(diào)用構(gòu)造函數(shù)。在C ++中,等效語法是
MySubClass: MyClass {public: MySubClass(int a, int b): MyClass(a+b) { }};
當(dāng)您在開放式大括號之前看到自己的初始化子句時,您知道它是特殊的。它在任何其余構(gòu)造函數(shù)運(yùn)行之前運(yùn)行,實(shí)際上在任何成員變量初始化之前運(yùn)行。Java并沒有那么不同。在構(gòu)造函數(shù)真正啟動之前,有一種方法可以在初始化子類的任何成員之前運(yùn)行一些代碼(其他構(gòu)造函數(shù))。這種方式是將“調(diào)用”(例如super
)放在第一行。(在某種程度上,在第一個開放式大括號之前,super
或者this
在第一個開放大括號之前,即使你在之后鍵入它,因?yàn)樗鼘⒃谀阃瓿伤袃?nèi)容之前執(zhí)行。)開放大括號之后的任何其他代碼(如int c = a + b;
)使編譯器說“哦,好吧,沒有其他構(gòu)造函數(shù),我們可以初始化所有內(nèi)容?!?nbsp;所以它會運(yùn)行并初始化你的超類和你的成員以及諸如此類的東西,然后在開放式大括號之后開始執(zhí)行代碼。
如果,幾行之后,它遇到一些代碼說“哦,當(dāng)你構(gòu)建這個對象時,這里是我希望你傳遞給基類的構(gòu)造函數(shù)的參數(shù)”,這已經(jīng)太晚了,它沒有有道理。所以你得到一個編譯器錯誤。

TA貢獻(xiàn)1788條經(jīng)驗(yàn) 獲得超4個贊
因此,它不會阻止您在調(diào)用super之前執(zhí)行邏輯。它只是阻止你執(zhí)行不能適合單個表達(dá)式的邏輯。
實(shí)際上你可以用幾次嘗試來執(zhí)行邏輯,你只需要將你的代碼包裝在一個靜態(tài)函數(shù)中并在super語句中調(diào)用它。
使用你的例子:
public class MySubClassC extends MyClass { public MySubClassC(Object item) { // Create a list that contains the item, and pass the list to super super(createList(item)); // OK } private static List createList(item) { List list = new ArrayList(); list.add(item); return list; }}

TA貢獻(xiàn)1906條經(jīng)驗(yàn) 獲得超3個贊
我完全同意,限制太強(qiáng)了。使用靜態(tài)輔助方法(如Tom Hawtin - 搭建建議)或?qū)⑺小皃re-super()計(jì)算”推入?yún)?shù)中的單個表達(dá)式并不總是可行的,例如:
class Sup { public Sup(final int x_) { //cheap constructor } public Sup(final Sup sup_) { //expensive copy constructor }}class Sub extends Sup { private int x; public Sub(final Sub aSub) { /* for aSub with aSub.x == 0, * the expensive copy constructor is unnecessary: */ /* if (aSub.x == 0) { * super(0); * } else { * super(aSub); * } * above gives error since if-construct before super() is not allowed. */ /* super((aSub.x == 0) ? 0 : aSub); * above gives error since the ?-operator's type is Object */ super(aSub); // much slower :( // further initialization of aSub }}
正如Carson Myers建議的那樣,使用“尚未構(gòu)造的對象”例外會有所幫助,但在每個對象構(gòu)造期間檢查這個會減慢執(zhí)行速度。我傾向于使Java編譯器更好地區(qū)分(而不是隨后禁止if語句但允許參數(shù)中的?-operator),即使這會使語言規(guī)范復(fù)雜化。

TA貢獻(xiàn)1799條經(jīng)驗(yàn) 獲得超6個贊
構(gòu)造函數(shù)按推導(dǎo)順序完成執(zhí)行是有道理的。因?yàn)槌惒恢廊魏巫宇?,所以它需要?zhí)行的任何初始化都與子類執(zhí)行的任何初始化分離,并且可能是先決條件。因此,它必須首先完成其執(zhí)行。
一個簡單的演示:
class A { A() { System.out.println("Inside A's constructor."); }}class B extends A { B() { System.out.println("Inside B's constructor."); }}class C extends B { C() { System.out.println("Inside C's constructor."); }}class CallingCons { public static void main(String args[]) { C c = new C(); }}
該程序的輸出是:
Inside A's constructorInside B's constructorInside C's constructor

TA貢獻(xiàn)1801條經(jīng)驗(yàn) 獲得超16個贊
在調(diào)用它的構(gòu)造函數(shù)之前,您可以使用匿名初始化程序塊初始化子項(xiàng)中的字段。這個例子將證明:
public class Test { public static void main(String[] args) { new Child(); }}class Parent { public Parent() { System.out.println("In parent"); }}class Child extends Parent { { System.out.println("In initializer"); } public Child() { super(); System.out.println("In child"); }}
這將輸出:
在父級中
初始化者
在子級中

TA貢獻(xiàn)1818條經(jīng)驗(yàn) 獲得超3個贊
我找到了一個woraround。
這不會編譯:
public class MySubClass extends MyClass { public MySubClass(int a, int b) { int c = a + b; super(c); // COMPILE ERROR doSomething(c); doSomething2(a); doSomething3(b); }}
這有效:
public class MySubClass extends MyClass { public MySubClass(int a, int b) { this(a + b); doSomething2(a); doSomething3(b); } private MySubClass(int c) { super(c); doSomething(c); }}

TA貢獻(xiàn)1829條經(jīng)驗(yàn) 獲得超7個贊
那是因?yàn)槟愕臉?gòu)造函數(shù)依賴于其他構(gòu)造函數(shù)。對于構(gòu)造函數(shù)正常工作,其他構(gòu)造函數(shù)必須正常工作,這是依賴的。這就是為什么必須首先檢查依賴構(gòu)造函數(shù),這些構(gòu)造函數(shù)首先在構(gòu)造函數(shù)中由this()或super()調(diào)用。如果由this()或super()調(diào)用的其他構(gòu)造函數(shù)有問題,那么什么點(diǎn)執(zhí)行其他語句,因?yàn)槿绻徽{(diào)用的構(gòu)造函數(shù)失敗,則所有構(gòu)造函數(shù)都會失敗。

TA貢獻(xiàn)1784條經(jīng)驗(yàn) 獲得超9個贊
實(shí)際上,super()
是構(gòu)造函數(shù)的第一個語句,因?yàn)橐_保它的超類在構(gòu)造子類之前是完全形成的。即使super()
你的第一個語句中沒有,編譯器也會為你添加它!
添加回答
舉報