Initialiseringsblock

Ett initialiseringsblock är ett koncept inom objektorienterad programmering , främst känt från Java-språket , som är en sekvens av kommandon som exekveras när man skapar ( laddar ) klasser och objekt . Designad för att kraftigt öka kraften hos konstruktören . Det finns två typer: ett statiskt initieringsblock, vanligtvis kallat ett statiskt block för kort, och ett dynamiskt initieringsblock (instansblock).

Motivation

När ett objekt skapas exekveras olika kommandon specificerade i konstruktorn. Ibland blir det nödvändigt att utöka syntaxens möjligheter. Vanligtvis finns ett dynamiskt block bara för bekvämlighets skull - det kan enkelt ersättas genom att lägga till en laddningsfunktion och anropa det från varje konstruktör. Det statiska blocket ökar dock programmets funktionalitet avsevärt och används därför mycket oftare.

Statiskt initieringsblock

Ett statiskt block är i huvudsak en konstruktor för hela klassen. Dess syntax är:

... static { // Statisk blockkod } ...

Den placeras mellan fältdefinitioner och klassfunktioner. Kommandon kommer att utföras i ett av två fall, vilket som kommer först:

  1. När du skapar det första objektet i klassen under programmets gång, innan du kör konstruktorn.
  2. Första gången en statisk funktion anropas, före exekvering.

Det vill säga, koden exekveras första gången klassen laddas. I det här exemplet vill vi skapa en klass som modellerar bilar tillverkade av ett visst företag och underhåller dem för att hålla reda på resten av deras existens, inklusive deras nuvarande situation, ägare, reparationshistorik etc. Varje objekt är en bil , och i klassen finns ett statiskt fält som innehåller en databas över alla bilar. Baserat på kartstrukturen när nyckeln är en bilmodell och innehållet är en grupp bilar av den modellen. Följande kod visar användningen av ett statiskt initieringsblock:

offentlig klass bil { statisk Karta < String , Set < Bil >> katalog ; statisk { catalog = new HashMap < String , Set < Car >> (); katalog . put ( "model105" , ny HashSet < Bil > ()); katalog . put ( "model125" , ny HashSet < Bil > ()); katalog . put ( "model140" , nytt HashSet < Bil > ()); katalog . put ( "model201" , nytt HashSet < Bil > ()); } offentlig bil ( strängmodell ) { _ katalog . ( modell ). lägg till ( detta ); // ... } // ... }

Linje 4 kan enkelt fästas på linje 2 utan behov av ett statiskt block. Raderna 5-8 visar dock behovet av det - förmågan att utföra komplexa kommandon på klassnivå, som på objektnivå skulle dyka upp i konstruktorn.

Dynamiskt initieringsblock

Ett dynamiskt block är ett tillägg till en konstruktor. Dess syntax är:

... { // Instans blockkod } ...

Den placeras mellan fältdefinitioner och klassfunktioner. Kommandona kommer att köras när objektet skapas. Det dynamiska blocket är ett tillägg för att göra konstruktorn lättare att skriva, och det ger ingen ytterligare funktionalitet. Det låter dig spara skapandet av en startfunktion och lägga till dess anrop från alla konstruktörer. Till exempel, kodavsnitt:

offentlig klass bil { statisk int count = 0 ; offentlig bil ( strängmodell ) { _ init (); // ... } offentlig bil ( strängmodell , dubbelt pris ) { _ init (); // ... } privat void init () { räkna ++ ; System . ut . println ( "Hej alla, vi har " + räkna + " bilar nu!" ); } // ... }

motsvarar kod:

offentlig klass bil { statisk int count = 0 ; offentlig bil ( strängmodell ) { _ // ... } offentlig bil ( strängmodell , dubbelt pris ) { _ // ... } { räkna ++ ; System . ut . println ( "Hej alla, vi har " + räkna + " bilar nu!" ); } // ... }

Ladda ordning

Under utformningen av Java-språket etablerades en konsekvent laddningsordning. Under klassladdning är ordningen följande:

  1. Definitioner av statiska fält för överordnade klasser.
  2. Initiering av statiska fält och exekvering av statiska block av överordnade klasser.
  3. Definitioner av statiska fält i en klass.
  4. Initiering av statiska fält och exekvering av statiska klassblock.

Sedan, när objektet skapas, är ordningen följande:

  1. Objektfältsdefinitioner från överordnade klasser.
  2. Fältinitiering och exekvering av dynamiska block från överordnade klasser.
  3. Utförande av konstruktörer från överordnade klasser.
  4. Definitioner av objektfält från dess klass.
  5. Fältinitiering och exekvering av dynamiska block från sin klass.
  6. Exekvera en konstruktor från sin klass.

När en förfaderkedja existerar utförs alla åtgärder först på den längst borta förfadern (klassobjekt) och sedan ner i kedjan i samma ordning till den aktuella klassen.

Om det finns mer än en typ i samma avsnitt ovan utförs stegen i den ordning de visas i programmet. Till exempel följande kod:

offentlig klass T { statisk int i = 5 ; statisk { i = 10 ; } statisk { i = i * 3 ; } }

tilldelar värdet 30 till variabeln i i varje objekt. Men koden:

offentlig klass T { statisk { i = 10 ; } statisk int i = 5 ; statisk { i = i * 3 ; } }

tilldelar värdet 15. Det vill säga, först skapas ett fält, och sedan utförs alla åtgärder i den ordning som anges i programmet - det första blocket, sedan fältinitieringen, sedan det andra blocket.

Möjliga problem

Att använda en variabel innan den definieras

I motsats till vad du kan förvänta dig, följande kod:

offentlig klass T { statisk { i = 5 ; i = i + 1 ; } statisk int i = 5 ; }

misslyckas med att kompilera på rad 4 eftersom den högra variabeln i användes innan den definierades, även om rad 3 kompileras och körs utan problem, även om det vänstra i:et på rad 4 inte ger något fel, och trots det faktum att under drift, när början av rad 4 nås definierades variabeln och fick ett värde. Detta beror på att placeringen av variabler (till exempel på rad 3) kontrolleras mot listan över variabler som för närvarande definieras under programkörning, inklusive alla statiska fält, och användningen av en sådan variabel kontrolleras mot platsen för definitionen.

Lokal statisk variabel

I motsats till vad du kan förvänta dig, följande kod:

offentlig klass T { statisk { int i = 10 ; } public static void main ( String [] args ) { System . ut . println ( i ); } }

kommer att misslyckas med kompileringen på rad 6 på grund av att variabeln inte är definierad, eftersom att definiera en variabel i ett statiskt block inte skapar en statisk variabel, bara en lokal variabel i det blocket. Det vill säga att koden inte motsvarar koden . static {int i = 10;}static int i = 10;

Se även

Länkar