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.