Nem hivatkozhat az „X” -re, mielőtt a Supertype konstruktort felhívták
1. Áttekintés
Ebben a rövid bemutatóban megmutatjuk, hogyan kaphatjuk meg a hibát Nem hivatkozhat „X” -re, mielőtt a szupertípus-konstruktort meghívnák, és hogyan kerülhető el.
2. Konstruktorok lánc
A konstruktor pontosan egy másik konstruktort hívhat meg. Ennek a hívásnak a testének első sorában kell lennie.
A kulcsszóval azonos osztályú konstruktort hívhatunk ez, vagy hívhatjuk a szuperosztály konstruktorát a kulcsszóval szuper.
Amikor egy konstruktor nem hív másik konstruktort, a fordító hívást ad a szuperosztály argumentum nélküli konstruktorához.
3. Összeállítási hibánk
Ez a hiba leáll megpróbálunk hozzáférni a példány szintű tagokhoz, mielőtt meghívnánk a konstruktor láncot.
Nézzünk meg pár módot, amiben összefuthatunk.
3.1. Hivatkozás egy példamódszerre
A következő példában a fordítási hibát látjuk Nem hivatkozhat „X” -re, mielőtt a szupertípus-konstruktort meghívnák az 5. sorban. Vegye figyelembe, hogy a konstruktor megpróbálja használni a példány metódust getErrorCode () túl korán:
public class A MyException kiterjeszti a RuntimeException {private int errorCode = 0; public MyException (String üzenet) {super (üzenet + getErrorCode ()); // fordítási hiba} public int getErrorCode () {return errorCode; }}
Ez azért hibás, mert until szuper() befejeződött, az osztálynak nincs példánya MyException. Ezért még nem hívhatjuk meg a példány metódust getErrorCode ().
3.2. Hivatkozás egy példány mezőre
A következő példában egy példánymező helyett egy példánymezővel látjuk a kivételünket. Vessünk egy pillantást arra, hogyan az első konstruktor megpróbál egy példánytagot használni, mielőtt maga a példány készen állna:
nyilvános osztály MyClass {private int myField1 = 10; privát int myField2; public MyClass () {this (myField1); // fordítási hiba} public MyClass (int i) {myField2 = i; }}
A példánymezőre csak az osztály inicializálása után lehet hivatkozni, vagyis bármilyen hívás után ez() vagy szuper().
Tehát miért nincs fordítói hiba a második konstruktorban, amely szintén példánymezőt használ?
Emlékezz arra minden osztály implicit módon származik az osztályból Tárgy, és így van egy implicit szuper() a fordító által hozzáadott hívás:
nyilvános MyClass (int i) {super (); // hozzáadta a fordító myField2 = i; }
Itt, TárgyA konstruktort hívják, mielőtt hozzáférnénk myField2, vagyis jól vagyunk.
4. Megoldások
A probléma első lehetséges megoldása triviális: nem hívjuk a második konstruktort. Az első konstruktorban kifejezetten azt tesszük, amit a második konstruktorban szerettünk volna megtenni.
Ebben az esetben másoljuk a myField1 -ba myField2:
nyilvános osztály MyClass {private int myField1 = 10; privát int myField2; nyilvános MyClass () {myField2 = myField1; } public MyClass (int i) {myField2 = i; }}
Általában azonban valószínűleg át kell gondolnunk az építés szerkezetét.
De ha jó okból hívjuk a második konstruktort, például a kód megismétlésének elkerülése érdekében, a kódot áthelyezhetjük egy módszerbe:
nyilvános osztály MyClass {private int myField1 = 10; privát int myField2; public MyClass () {setupMyFields (myField1); } public MyClass (int i) {setupMyFields (i); } private void setupMyFields (int i) {myField2 = i; }}
Ez megint azért működik, mert a fordító a módszer meghívása előtt implicit módon hívta a konstruktor láncot.
A harmadik megoldás az lehet, hogy használjuk statikus mezők vagy módszerek. Ha megváltozunk myField1 statikus állandóra, akkor a fordító is örül:
nyilvános osztály MyClass {private static final int SOME_CONSTANT = 10; privát int myField2; public MyClass () {this (SOME_CONSTANT); } public MyClass (int i) {myField2 = i; }}
Meg kell jegyeznünk, hogy a mező készítése statikus azt jelenti, hogy megosztottá válik az objektum összes példányával, így nem könnyű változtatni túl könnyedén.
Mert statikus a helyes válaszhoz erős okra van szükségünk. Például lehet, hogy az érték valójában nem mező, hanem konstans, ezért van értelme elkészíteni statikus és végső. Lehet, hogy az a konstrukciós módszer, amelyet meg akartunk hívni, nem igényel hozzáférést az osztály példánytagjaihoz, vagyis annak kellene lennie statikus.
5. Következtetés
Ebben a cikkben láttuk, hogyan lehet hivatkozni a példány tagjaira a szuper() vagy ez() A call fordítási hibát ad. Láttuk, hogy ez történik egy kifejezetten deklarált alaposztálynál és az implicitnél is Tárgy alaposztály.
Megmutattuk azt is, hogy ez a kivitelező tervezésének kérdése, és megmutattuk, hogyan lehet ezt kijavítani úgy, hogy megismételjük a kódot a kivitelezőben, delegálunk egy utómunkálati beállítási módszerre, vagy állandó értékek vagy statikus módszerek használatával segítjük a kivitelezést .
Mint mindig, ennek a példának a forráskódja megtalálható a GitHubon.