1. Initialisering av variabler
Som du redan vet kan du deklarera flera variabler i din klass, och inte bara deklarera dem, utan också omedelbart initiera dem med deras initiala värden.
Och samma variabler kan också initieras i en konstruktor. Detta innebär att dessa variabler i teorin skulle kunna tilldelas värden två gånger. Exempel
Koda | Notera |
---|---|
|
Variabeln age tilldelas ett initialvärde. Initialvärdet skrivs över. Åldervariabeln lagrar sitt initiala värde. |
|
Detta är tillåtet: den första konstruktorn kommer att anropas |
|
Detta är tillåtet: den andra konstruktören kommer att anropas |
Detta är vad som händer när Cat cat = new Cat("Whiskers", 2);
det körs:
- Ett
Cat
objekt skapas - Alla instansvariabler initieras med sina initiala värden
- Konstruktorn anropas och dess kod exekveras.
Med andra ord, variablerna får först sina initiala värden, och först därefter exekveras konstruktorns kod.
2. Initieringsordning av variabler i en klass
Variabler initieras inte bara innan konstruktorn körs – de initieras i en väldefinierad ordning: den ordning i vilken de deklareras i klassen.
Låt oss titta på lite intressant kod:
Koda | Notera |
---|---|
|
Den här koden kommer inte att kompileras, eftersom det inte finns några och variabler ännu när a
variabeln skapas . Men du kan skriva din kod på följande sätt - den här koden kommer att kompileras och fungerar bra.b
c
Koda | Notera |
---|---|
|
0 0+2 0+2+3 |
Men kom ihåg att din kod måste vara transparent för andra utvecklare. Det är bättre att inte använda sådana här tekniker, eftersom det försämrar kodens läsbarhet.
Här måste vi komma ihåg att innan variabler tilldelas ett värde har de ett standardvärde . För int
typen är detta noll.
När JVM initierar a
variabeln tilldelar den helt enkelt standardvärdet för int-typen: 0.
När den når b
, kommer a-variabeln redan att vara känd och ha ett värde, så JVM kommer att tilldela den värdet 2.
Och när den når c
variabeln kommer variablerna a
och b
redan att initieras, så JVM kommer enkelt att beräkna det initiala värdet för c
: 0+2+3.
Om du skapar en variabel i en metod kan du inte använda den om du inte tidigare har tilldelat den ett värde. Men detta är inte sant för variablerna i en klass! Om ett initialvärde inte tilldelas en variabel i en klass, tilldelas det ett standardvärde.
3. Konstanter
Medan vi analyserar hur objekt skapas är det värt att beröra initialiseringen av konstanter, dvs variabler med modifieraren final
.
Om en variabel har modifieraren final
måste den tilldelas ett initialt värde. Du vet redan detta, och det är inget förvånande med det.
Men vad du inte vet är att du inte behöver tilldela startvärdet direkt om du tilldelar det i konstruktorn. Detta kommer att fungera bra för en slutlig variabel. Det enda kravet är att om du har flera konstruktörer måste en slutlig variabel tilldelas ett värde i varje konstruktor.
Exempel:
public class Cat
{
public final int maxAge = 25;
public final int maxWeight;
public Cat (int weight)
{
this.maxWeight = weight; // Assign an initial value to the constant
}
}
4. Koda i en konstruktor
Och några fler viktiga anteckningar om konstruktörer. Senare, när du fortsätter att lära dig Java, kommer du att stöta på saker som arv, serialisering, undantag, etc. De påverkar alla konstruktörernas arbete i olika grad. Det är ingen mening att dyka djupt in i dessa ämnen nu, men vi är skyldiga att åtminstone beröra dem.
Till exempel, här är en viktig kommentar om konstruktörer. I teorin kan du skriva kod av vilken komplexitet som helst i en konstruktor. Men gör inte det här. Exempel:
|
Öppna en fil läs ström Läs filen till en byte array Spara byte arrayen som en sträng Visa filens innehåll på skärmen |
I FilePrinter-klasskonstruktorn öppnade vi omedelbart en byteström på en fil och läste dess innehåll. Detta är komplext beteende och kan resultera i fel.
Tänk om det inte fanns någon sådan fil? Vad händer om det uppstod problem med att läsa filen? Tänk om den var för stor?
Komplex logik innebär en hög sannolikhet för fel och det betyder att koden måste hantera undantag korrekt.
Exempel 1 — Serialisering
I ett standard Java-program finns det många situationer där du inte är den som skapar objekt i din klass. Anta till exempel att du bestämmer dig för att skicka ett objekt över nätverket: i det här fallet kommer Java-maskinen själv att konvertera ditt objekt till en uppsättning byte, skicka det och återskapa objektet från uppsättningen byte.
Men anta att din fil inte finns på den andra datorn. Det kommer att uppstå ett fel i konstruktorn, och ingen kommer att hantera det. Och det är ganska kapabelt att få programmet att avslutas.
Exempel 2 — Initiering av fält i en klass
Om din klasskonstruktor kan kasta markerade undantag, dvs är markerad med nyckelordet throws, måste du fånga de angivna undantagen i metoden som skapar ditt objekt.
Men vad händer om det inte finns någon sådan metod? Exempel:
Koda | Notera |
---|---|
|
Den här koden kommer inte att kompileras. |
Klasskonstruktorn FilePrinter
kan kasta ett markerat undantag , vilket innebär att du inte kan skapa ett FilePrinter
objekt utan att linda in det i ett försök-fångst-block. Och ett försök-fångst-block kan bara skrivas i en metod
5. Basklasskonstruktör
På tidigare lektioner diskuterade vi arv lite. Tyvärr är vår fullständiga diskussion om arv och OOP reserverad för nivån dedikerad till OOP, och nedärvning av konstruktörer är redan relevant för oss.
Om din klass ärver en annan klass, kommer ett objekt från den överordnade klassen att bäddas in i ett objekt i din klass. Dessutom har den överordnade klassen sina egna variabler och sina egna konstruktorer.
Det betyder att det är mycket viktigt för dig att veta och förstå hur variabler initieras och konstruktörer anropas när din klass har en överordnad klass och du ärver dess variabler och metoder.
Klasser
Hur vet vi i vilken ordning variabler initieras och konstruktörer anropas? Låt oss börja med att skriva koden för två klasser. Den ena kommer att ärva den andra:
Koda | Notera |
---|---|
|
Klassen ChildClass ärver ParentClass klassen. |
Vi måste bestämma i vilken ordning variabler initieras och konstruktörer anropas. Loggning hjälper oss att göra detta.
Skogsavverkning
Loggning är processen att registrera åtgärder som utförs av ett program när det körs, genom att skriva dem till konsolen eller en fil.
Det är ganska enkelt att fastställa att konstruktören har anropats: i konstruktörens kropp, skriv ett meddelande till konsolen. Men hur kan du se om en variabel har initierats?
Egentligen är detta inte särskilt svårt: skriv en speciell metod som kommer att returnera värdet som används för att initiera variabeln och logga initieringen. Så här kan koden se ut:
Slutlig kod
|
Skapa ett ChildClass objekt Den här metoden skriver den skickade texten till konsolen och returnerar den också. Deklarera ParentClass klassen Display text och initialisera även variablerna med den. Skriv ett meddelande om att konstruktören har anropats. Ignorera returvärdet. Deklarera ChildClass klassen Display text och initialisera även variablerna med den. Skriv ett meddelande om att konstruktören har anropats. Ignorera returvärdet. |
Om du kör den här koden kommer text att visas på skärmen enligt följande:
Konsolutdata för metodenMain.print() |
---|
|
Så du kan alltid personligen se till att variablerna i en klass initieras innan konstruktorn anropas. En basklass initieras helt innan initieringen av den ärvda klassen.
GO TO FULL VERSION