Kan ikke referere til "X" før Supertype Constructor har blitt kalt

1. Oversikt

I denne korte opplæringen viser vi hvordan vi kan få feilen Kan ikke referere til "X" før supertypekonstruktøren har blitt kalt, og hvordan du kan unngå det.

2. Konstruktørkjede

En konstruktør kan ringe nøyaktig en annen konstruktør. Denne samtalen må være i første linje i kroppen.

Vi kan ringe en konstruktør av samme klasse med nøkkelordet dette, eller vi kan ringe en konstruktør av superklassen med nøkkelordet super.

Når en konstruktør ikke ringer til en annen konstruktør, legger kompilatoren et anrop til konstruktøren uten argument i superklassen.

3. Kompileringsfeilen vår

Denne feilen koker ned til prøver å få tilgang til instansnivå medlemmer før vi påkaller konstruktørkjeden.

La oss se et par måter vi kan komme på dette.

3.1. Henviser til en instansemetode

I neste eksempel ser vi kompileringsfeilen Kan ikke referere til "X" før supertypekonstruktøren har blitt kalt på linje 5. Merk at konstruktøren prøver å bruke forekomstmetoden getErrorCode () for tidlig:

offentlig klasse MyException utvider RuntimeException {private int errorCode = 0; offentlig MyException (strengmelding) {super (melding + getErrorCode ()); // kompileringsfeil} offentlig int getErrorCode () {return errorCode; }} 

Disse feilene fordi until super() har fullført, det er ikke en forekomst av klassen MyException. Derfor kan vi ennå ikke ringe til forekomstmetoden getErrorCode ().

3.2. Henviser til et instansfelt

I det neste eksemplet ser vi unntaket vårt med et forekomstfelt i stedet for en forekomstmetode. La oss ta en titt på hvordan den første konstruktøren prøver å bruke et forekomstmedlem før selve forekomsten er klar:

offentlig klasse MyClass {private int myField1 = 10; privat int myField2; offentlig MyClass () {dette (myField1); // kompileringsfeil} offentlig MyClass (int i) {myField2 = i; }}

En referanse til et forekomstfelt kan bare gjøres etter at klassen er initialisert, det vil si etter en samtale til dette() eller super().

Så hvorfor er det ingen kompilatorfeil i den andre konstruktøren, som også bruker et forekomstfelt?

Husk at alle klassene er implisitt avledet fra klassen Gjenstand, og så er det implisitt super() samtale lagt til av kompilatoren:

offentlig MyClass (int i) {super (); // lagt til av kompilator myField2 = i; } 

Her, Gjenstand’S konstruktør blir ringt før vi får tilgang myField2, noe som betyr at vi har det bra.

4. Løsninger

Den første mulige løsningen på dette problemet er trivielt: vi kaller ikke den andre konstruktøren. Vi gjør eksplisitt i den første konstruktøren hva vi ønsket å gjøre i den andre konstruktøren.

I dette tilfellet kopierer vi verdien av myField1 inn i myField2:

offentlig klasse MyClass {private int myField1 = 10; privat int myField2; offentlig MyClass () {myField2 = myField1; } offentlig MyClass (int i) {myField2 = i; }} 

Generelt, skjønt, Vi må sannsynligvis tenke nytt på strukturen til det vi bygger.

Men hvis vi kaller den andre konstruktøren av en god grunn, for eksempel for å unngå å gjenta kode, vi kan flytte koden til en metode:

offentlig klasse MyClass {private int myField1 = 10; privat int myField2; offentlig MyClass () {setupMyFields (myField1); } offentlig MyClass (int i) {setupMyFields (i); } privat tomrom setupMyFields (int i) {myField2 = i; }} 

Igjen, dette fungerer fordi kompilatoren implisitt har ringt konstruktorkjeden før den påkaller metoden.

En tredje løsning kan være at vi bruker statiske felt eller metoder. Hvis vi endrer oss myField1 til en statisk konstant, så er kompilatoren også fornøyd:

offentlig klasse MyClass {private static final int SOME_CONSTANT = 10; privat int myField2; offentlig MyClass () {dette (SOME_CONSTANT); } offentlig MyClass (int i) {myField2 = i; }} 

Vi bør merke oss at det å lage et felt statisk betyr at det blir delt med alle forekomster av dette objektet, så det er ikke en endring å gjøre for lett.

Til statisk for å være det rette svaret, trenger vi en sterk grunn. For eksempel, kanskje verdien ikke egentlig er et felt, men i stedet en konstant, så det er fornuftig å lage det statisk og endelig. Kanskje trenger ikke byggemetoden vi ønsket å ringe tilgang til forekomsten av klassen, noe som betyr at den burde være statisk.

5. Konklusjon

Vi så i denne artikkelen hvordan det henvises til instansemedlemmer før super() eller dette() samtale gir en kompileringsfeil. Vi så dette skje med en eksplisitt erklært basisklasse og også med den implisitte Gjenstand baseklasse.

Vi demonstrerte også at dette er et problem med konstruktørens design og viste hvordan dette kan løses ved å gjenta kode i konstruktøren, delegere til en installasjonsmetode etter bygging, eller bruk av konstante verdier eller statiske metoder for å hjelpe til med konstruksjonen .

Som alltid kan kildekoden for dette eksemplet finnes på GitHub.


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