Kan niet verwijzen naar "X" voordat Supertype Constructor is aangeroepen

1. Overzicht

In deze korte tutorial laten we zien hoe we de fout kunnen krijgen Kan niet verwijzen naar "X" voordat supertype constructor is aangeroepen, en hoe u dit kunt vermijden.

2. Constructeursketen

Een constructor kan precies één andere constructor aanroepen. Deze aanroep moet in de eerste regel van zijn hoofdtekst staan.

We kunnen een constructor van dezelfde klasse aanroepen met het trefwoord dit, of we kunnen een constructor van de superklasse aanroepen met het trefwoord super.

Als een constructor geen andere constructor aanroept, voegt de compiler een aanroep toe aan de constructor zonder argument van de superklasse.

3. Onze compilatiefout

Deze fout komt neer op proberen toegang te krijgen tot leden op instantieniveau voordat we de constructorketen aanroepen.

Laten we eens kijken naar een aantal manieren waarop we dit kunnen tegenkomen.

3.1. Verwijzend naar een instantiemethode

In het volgende voorbeeld zien we de compilatiefout Kan niet verwijzen naar "X" voordat de constructor supertype is aangeroepen op regel 5. Merk op dat de constructor de instantiemethode probeert te gebruiken getErrorCode () te vroeg:

openbare klasse MyException breidt RuntimeException uit {private int errorCode = 0; openbare MyException (String-bericht) {super (bericht + getErrorCode ()); // compilatiefout} public int getErrorCode () {return errorCode; }} 

Dit fout omdat, until super() heeft afgerond, is er geen instantie van de klasse MyException. Daarom kunnen we de instantiemethode nog niet aanroepen getErrorCode ().

3.2. Verwijzend naar een instantieveld

In het volgende voorbeeld zien we onze uitzondering met een instantieveld in plaats van een instantiemethode. Laten we eens kijken hoe de eerste constructor probeert een instantie-lid te gebruiken voordat de instantie zelf klaar is:

openbare klasse MyClass {privé int myField1 = 10; privé int myField2; openbare MyClass () {dit (myField1); // compilatiefout} openbare MyClass (int i) {myField2 = i; }}

Een verwijzing naar een instantieveld kan alleen worden gemaakt nadat de klasse ervan is geïnitialiseerd, dat wil zeggen na een aanroep naar dit() of super().

Dus waarom is er geen compilatiefout in de tweede constructor, die ook een instantieveld gebruikt?

Onthoud dat alle klassen zijn impliciet afgeleid van klasse Voorwerp, en dus is er een impliciete super() oproep toegevoegd door de compiler:

openbare MyClass (int i) {super (); // toegevoegd door compiler myField2 = i; } 

Hier, Voorwerp‘S constructor wordt gebeld voordat we toegang krijgen myField2, wat betekent dat we in orde zijn.

4. Oplossingen

De eerste mogelijke oplossing voor dit probleem is triviaal: we noemen de tweede constructor niet. We doen expliciet in de eerste constructor wat we wilden doen in de tweede constructor.

In dit geval kopiëren we de waarde van myField1 in myField2:

openbare klasse MyClass {privé int myField1 = 10; privé int myField2; openbare MyClass () {myField2 = myField1; } openbare MyClass (int i) {myField2 = i; }} 

In het algemeen echter we moeten waarschijnlijk de structuur van wat we bouwen opnieuw bekijken.

Maar als we de tweede constructor om een ​​goede reden aanroepen, bijvoorbeeld om herhaling van code te voorkomen, we kunnen de code naar een methode verplaatsen:

openbare klasse MyClass {privé int myField1 = 10; privé int myField2; openbare MyClass () {setupMyFields (myField1); } openbare MyClass (int i) {setupMyFields (i); } private leegte setupMyFields (int i) {myField2 = i; }} 

Nogmaals, dit werkt omdat de compiler impliciet de constructorketen heeft aangeroepen voordat de methode werd aangeroepen.

Een derde oplossing zou kunnen zijn dat we deze gebruiken statische velden of methoden. Als we veranderen myField1 naar een statische constante, dan is de compiler ook blij:

openbare klasse MyClass {privé statische finale int SOME_CONSTANT = 10; privé int myField2; openbare MyClass () {dit (SOME_CONSTANT); } openbare MyClass (int i) {myField2 = i; }} 

We moeten opmerken dat het maken van een veld statisch betekent dat het wordt gedeeld met alle instanties van dit object, dus het is niet een te lichte wijziging.

Voor statisch om het juiste antwoord te zijn, hebben we een sterke reden nodig. Misschien is de waarde bijvoorbeeld niet echt een veld, maar in plaats daarvan een constante, dus is het logisch om het te maken statisch en laatste. Misschien heeft de constructiemethode die we wilden aanroepen geen toegang nodig tot de instantieleden van de klasse, wat betekent dat dit zou moeten zijn statisch.

5. Conclusie

We hebben in dit artikel gezien hoe een verwijzing naar instantieleden vóór de super() of dit() call geeft een compilatiefout. We zagen dit gebeuren met een expliciet gedeclareerde basisklasse en ook met de impliciete Voorwerp basisklasse.

We hebben ook aangetoond dat dit een probleem is met het ontwerp van de constructor en laten zien hoe dit kan worden opgelost door code in de constructor te herhalen, te delegeren naar een post-constructie setup-methode, of het gebruik van constante waarden of statische methoden om te helpen bij de constructie. .

Zoals altijd is de broncode voor dit voorbeeld te vinden op GitHub.


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