Ne može se uputiti na “X” prije nego što je pozvan konstruktor supertipa

1. Pregled

U ovom kratkom uputstvu pokazat ćemo kako možemo doći do pogreške Ne može se uputiti na “X” prije nego što je pozvan konstruktor supertipa, i kako to izbjeći.

2. Lanac konstruktora

Konstruktor može pozvati točno jedan drugi konstruktor. Ovaj poziv mora biti u prvom redu tijela.

Konstruktor iste klase možemo nazvati s ključnom riječi ovaj, ili možemo nazvati konstruktor superklase s ključnom riječi super.

Kada konstruktor ne pozove drugi konstruktor, kompajler dodaje poziv konstruktoru bez argumenta superklase.

3. Naša pogreška pri kompilaciji

Ova se pogreška svodi na pokušavajući pristupiti članovima na razini instance prije nego što pozovemo lanac konstruktora.

Pogledajmo nekoliko načina na koje bismo mogli naletjeti na ovo.

3.1. Pozivajući se na metodu instance

U sljedećem primjeru vidjet ćemo pogrešku kompilacije Ne može se uputiti na “X” prije nego što je pozvan konstruktor supertipa u retku 5. Imajte na umu da konstruktor pokušava koristiti metodu instance getErrorCode () prerano:

javna klasa MyException proširuje RuntimeException {private int errorCode = 0; javni MyException (niz poruka) {super (poruka + getErrorCode ()); // pogreška kompilacije} public int getErrorCode () {return errorCode; }} 

Ova pogreška jer, until super() je završio, ne postoji primjer klase MyException. Stoga još ne možemo uputiti poziv na metodu instance getErrorCode ().

3.2. Pozivajući se na polje instance

U sljedećem primjeru vidimo našu iznimku s poljem instance umjesto metode instance. Pogledajmo kako prvi konstruktor pokušava upotrijebiti člana instance prije nego što instanca bude spremna:

javna klasa MyClass {private int myField1 = 10; private int myField2; javni MyClass () {this (myField1); // pogreška kompilacije} javni MyClass (int i) {myField2 = i; }}

Referenca na polje instance može se izvršiti tek nakon što je njegova klasa inicijalizirana, što znači nakon bilo kojeg poziva na ovaj() ili super().

Pa, zašto u drugom konstruktoru, koji također koristi polje instance, nema pogreške prevoditelja?

Zapamti to sve su klase implicitno izvedene iz klase Objekt, i tako postoji implicitno super() poziv koji je dodao prevodilac:

javni MyClass (int i) {super (); // dodao kompajler myField2 = i; } 

Ovdje, ObjektKonstruktor se poziva prije nego što pristupimo myField2, što znači da smo dobro.

4. Rješenja

Prvo moguće rješenje ovog problema je trivijalno: drugi konstruktor ne zovemo. U prvom konstruktoru radimo izričito ono što smo željeli u drugom konstruktoru.

U ovom bismo slučaju kopirali vrijednost myField1 u myField2:

javna klasa MyClass {private int myField1 = 10; private int myField2; javni MyClass () {myField2 = myField1; } javni MyClass (int i) {myField2 = i; }} 

Općenito, ipak, vjerojatno moramo preispitati strukturu onoga što gradimo.

Ali, ako drugi konstruktor zovemo iz dobrog razloga, na primjer, kako bismo izbjegli ponavljanje koda, možemo premjestiti kod u metodu:

javna klasa MyClass {private int myField1 = 10; private int myField2; javni MyClass () {setupMyFields (myField1); } javni MyClass (int i) {setupMyFields (i); } private void setupMyFields (int i) {myField2 = i; }} 

Opet, ovo djeluje jer je prevoditelj implicitno pozvao lanac konstruktora prije pozivanja metode.

Treće rješenje može biti ono što koristimo statička polja ili metode. Ako se promijenimo myField1 na statičku konstantu, tada je i prevodilac sretan:

javna klasa MyClass {private static final int SOME_CONSTANT = 10; private int myField2; javni MyClass () {this (SOME_CONSTANT); } javni MyClass (int i) {myField2 = i; }} 

Trebali bismo napomenuti da izrada polja statički znači da se dijeli sa svim instancama ovog objekta, tako da to nije promjena koju treba napraviti previše olako.

Za statički da bismo bili pravi odgovor, potreban nam je jak razlog. Na primjer, možda vrijednost zapravo nije polje, već je konstanta, pa ima smisla to unijeti statički i konačni. Možda metodu konstrukcije koju smo željeli nazvati ne treba pristup članovima instance klase, što znači da bi trebao biti statički.

5. Zaključak

U ovom smo članku vidjeli kako upućivanje na članove instance prije super() ili ovaj() poziv daje pogrešku u kompilaciji. Vidjeli smo da se to dogodilo s eksplicitno deklariranom osnovnom klasom i također s implicitnom Objekt osnovna klasa.

Također smo pokazali da je ovo problem s dizajnom konstruktora i pokazali smo kako se to može popraviti ponavljanjem koda u konstruktoru, delegiranjem na metodu postavljanja nakon konstrukcije ili upotrebom konstantnih vrijednosti ili statičkih metoda za pomoć u konstrukciji .

Kao i uvijek izvorni kod za ovaj primjer možete pronaći na GitHubu.


$config[zx-auto] not found$config[zx-overlay] not found