現(xiàn)在該輪到你寫一些代碼了。假設(shè)你有一個(gè)稱為Thing的庫類,它的構(gòu)造器將接受一個(gè)int參數(shù):
public class Thing {
public Thing(int i) { ... }
...
}
Thing實(shí)例沒有提供任何可以獲取其構(gòu)造器參數(shù)的值的途徑。因?yàn)門hing是一個(gè)庫類,所以你不具有訪問其內(nèi)部的權(quán)限,因此你不能修改它。
假設(shè)你想編寫一個(gè)稱為MyThing的子類,其構(gòu)造器將通過調(diào)用SomeOtherClass.func()方法來計(jì)算超類構(gòu)造器的參數(shù)。這個(gè)方法返回的值被一個(gè)個(gè)的調(diào)用以不可預(yù)知的方式所修改。最后,假設(shè)你想將這個(gè)曾經(jīng)傳遞給超類構(gòu)造器的值存儲到子類的一個(gè)final實(shí)例域中,以供將來使用。那么下面就是你自然會寫出的代碼:
public class MyThing extends Thing {
private final int arg;
public MyThing() {
super(arg = SomeOtherClass.func());
...
}
}
遺憾的是,這個(gè)程序是非法的。如果你嘗試著去編譯它,那么你將得到一條像下面這樣的錯(cuò)誤消息:
MyThing.java:
can’t reference arg before supertype constructor has been called
super(arg = SomeOtherClass.func());
^
你怎樣才能重寫MyThing以實(shí)現(xiàn)想要的效果呢?MyThing()構(gòu)造器必須是線程安全的:多個(gè)線程可能會并發(fā)地調(diào)用它。
這個(gè)解決方案內(nèi)在地就是線程安全的和優(yōu)雅的,它涉及對MyThing中第二個(gè)私有的構(gòu)造器的運(yùn)用:
public class MyThing extends Thing {
private final int arg;
public MyThing() {
this(SomeOtherClass.func());
}
private MyThing(int i) {
super(i);
arg = i;
}
}
這個(gè)解決方案使用了交替構(gòu)造器調(diào)用機(jī)制(alternate constructor invocation)[JLS 8.8.7.1]。這個(gè)特征允許一個(gè)類中的某個(gè)構(gòu)造器鏈接調(diào)用同一個(gè)類中的另一個(gè)構(gòu)造器。在本例中,MyThing()鏈接調(diào)用了私有構(gòu)造器MyThing(int),它執(zhí)行了所需的實(shí)例初始化。在這個(gè)私有構(gòu)造器中,表達(dá)式SomeOtherClass.func()的值已經(jīng)被捕獲到了變量i中,并且它可以在超類構(gòu)造器返回之后存儲到final類型的域param中。
通過本謎題所展示的私有構(gòu)造器捕獲(Private Constructor Capture)慣用法是一種非常有用的模式,你應(yīng)該把它添加到你的技巧庫中。我們已經(jīng)看到了某些真的是很丑陋的代碼,它們本來是可以通過使用本模式而避免如此丑陋的。
public class Thing {
public Thing(int i) { ... }
...
}
Thing實(shí)例沒有提供任何可以獲取其構(gòu)造器參數(shù)的值的途徑。因?yàn)門hing是一個(gè)庫類,所以你不具有訪問其內(nèi)部的權(quán)限,因此你不能修改它。
假設(shè)你想編寫一個(gè)稱為MyThing的子類,其構(gòu)造器將通過調(diào)用SomeOtherClass.func()方法來計(jì)算超類構(gòu)造器的參數(shù)。這個(gè)方法返回的值被一個(gè)個(gè)的調(diào)用以不可預(yù)知的方式所修改。最后,假設(shè)你想將這個(gè)曾經(jīng)傳遞給超類構(gòu)造器的值存儲到子類的一個(gè)final實(shí)例域中,以供將來使用。那么下面就是你自然會寫出的代碼:
public class MyThing extends Thing {
private final int arg;
public MyThing() {
super(arg = SomeOtherClass.func());
...
}
}
遺憾的是,這個(gè)程序是非法的。如果你嘗試著去編譯它,那么你將得到一條像下面這樣的錯(cuò)誤消息:
MyThing.java:
can’t reference arg before supertype constructor has been called
super(arg = SomeOtherClass.func());
^
你怎樣才能重寫MyThing以實(shí)現(xiàn)想要的效果呢?MyThing()構(gòu)造器必須是線程安全的:多個(gè)線程可能會并發(fā)地調(diào)用它。
這個(gè)解決方案內(nèi)在地就是線程安全的和優(yōu)雅的,它涉及對MyThing中第二個(gè)私有的構(gòu)造器的運(yùn)用:
public class MyThing extends Thing {
private final int arg;
public MyThing() {
this(SomeOtherClass.func());
}
private MyThing(int i) {
super(i);
arg = i;
}
}
這個(gè)解決方案使用了交替構(gòu)造器調(diào)用機(jī)制(alternate constructor invocation)[JLS 8.8.7.1]。這個(gè)特征允許一個(gè)類中的某個(gè)構(gòu)造器鏈接調(diào)用同一個(gè)類中的另一個(gè)構(gòu)造器。在本例中,MyThing()鏈接調(diào)用了私有構(gòu)造器MyThing(int),它執(zhí)行了所需的實(shí)例初始化。在這個(gè)私有構(gòu)造器中,表達(dá)式SomeOtherClass.func()的值已經(jīng)被捕獲到了變量i中,并且它可以在超類構(gòu)造器返回之后存儲到final類型的域param中。
通過本謎題所展示的私有構(gòu)造器捕獲(Private Constructor Capture)慣用法是一種非常有用的模式,你應(yīng)該把它添加到你的技巧庫中。我們已經(jīng)看到了某些真的是很丑陋的代碼,它們本來是可以通過使用本模式而避免如此丑陋的。