Java lathund #4 - Konstruktor, metoder och skapandet av objekt
Förord
I denna artikel tänkte jag att vi skulle gå in mer på hur man skapar objekt från klasser och sedan använder dem till något genom att anropa ett objekts metoder. Vi ska också titta lite ”bakom kulisserna” vad som sker när ett objekt skapas.Innehåll
»»
»
»
»
»
»
Relaterade artiklar
» Java lathund #1 - Hello World» Java lathund #2 - Klass och main-metod
» Java lathund #3 - Reserverade ord och primitiva datatyper
Introduktion
Som tidigare sagt så är Java applikationer uppbyggt av ett antal samverkande objekt. Men hur jobbar man med dessa objekt? Hur skapar man dem, d.v.s. ger dem ”liv”? Hur får man objekten att utföra saker åt oss?
Jag tänkte att vi först skulle gå in på hur metoder ser ut i Java. Därefter tänkte jag visa lite om hur man skapar nya objekt och får dem att utföra saker åt oss. Och till sist tänkte jag berätta lite om vad som händer när ett nytt objekt skapas.
Metoder i Java
Vi har sett i tidigare artiklar hur ett metod-block ser ut. Vi har också kikat på den speciella main-metoden. Nu tänkte jag att vi skulle försöka oss på metoder som har ett specifikt syfte.
Säg att vi vill skapa en klass som representerar en ”generell människa” (om det nu finns).
Vi börjar med att skapa ett klass-block:
class Human {
}
Vilka egenskaper vill vi att vår ”generella människa” skall ha? Ja, vi kan ju ha attribut som lagrar information om ålder och namn. Alla människor har ju en ålder och kallar sig något, eller hur?
Detta skulle i kod se ut så här:
class Human {
int age; //Attribut för ålder
String name; //Attribut för namn
}
Vilka metoder vill vi att vår klass ska ha då?
Ja, det vore ju bra om vår ”generella människa” kunde svara på hur gammal hon är och vad hon heter.
Då skapar vi väl metoder för det. Jag tar en metod i taget.
class Human {
int age;
String name;
// Metod som returnerar objektets ålder
int myAge() {
return age;
}
}
Nu har vi skapat en metod som kan svara på hur gammal vår “generella människa” är. Detta är en metod som kan returnera något tillbaka när man frågar.
Tidigare har vi sett att man inleder en metod med void om man inte vill att metoden ska returnera något. I detta fall börjar vi med att ange vilken datatyp som vi får tillbaka vårat svar i. Eftersom vi har representerat attributet age som en int så bör vi ju rimligtvis få svaret tillbaka som en int.
Alltså när vi frågar objektet: ”Hur gammal är du?”, får vi tillbaka svaret som ett heltal.
Efter när vi har definierat vilken returtyp metoden ska ha anger vi metodnamnet och de två paranteserna. Vi har sett i en artikel tidigare att en metod kan ta en inparameter mellan de två paranteserna, men det behövs inte här.
Sedan har vi den startande måsvingen som säger: ”Mertoden startar här” och sen kommer en kodsats som utför något i vår metod. Vi vill ju att vår metod ska svara på ”Hur gammal är du?”. Detta löser vi genom att returnera detta objekts attribut som den lagrar sin ålder i, age. Om man vill returnera något skriver man return följt av det man vill returnera.
Info!
Något jag inte har nämnt tidigare är att man alltid avslutar en kodsats i Java med ett semikolon ( ; ).
Till sist har vi den avslutande måsvingen som säger: ”Nu är metoden slut”.
Jag fyller på i klassen med den andra metoden för att erhålla objektets namn. Lägg märke till att jag returnerar en annan datatyp när jag ber objektet om sitt namn.
class Human {
int age; //Attribut för ålder
String name; //Attribut för namn
int myAge() {
return age;
}
String myName() {
return name;
}
}
Det är egentligen inte en datatyp jag returnerar, utan jag returnerar ett objekt av typen String, vilket är fullt acceptabelt i Java. Man kan alltså returnera hela objekt.
Det var väl inte så svårt?
Men hur får vårat objekt en ålder och ett namn?
Jo, det får Ni själva ange när Ni leker ”den stora skaparen” och ger massa olika objekt liv i Er applikation. Man får helt enkelt skapa metoder för det också.
Men kan vi inte bara skriva...
class human {
int age = 10;
}
...???
Njae, då kommer ju varje objekt Ni skapar att ha åldern 10 och vill vi verkligen det? Jag föreslår följande lösning:
class Human {
int age;
String name;
int myAge() {
return age;
}
String myName() {
return name;
}
// Metod som ger objektet dess ålder
void setAge(int age) {
this.age = age;
}
}
Denna metod börjar med void, vilket betyder att metoden inte returnerar något. Sedan följer som vanligt ett metodnamn.
Den här metoden kan dock ta en inparameter till metoden. Detta anges mellan de två paranteserna. Först anger vi vilken datatyp som metoden kan ta emot och sedan ger vi inparametern ett namn. Eftersom vi vill med denna metod ge objektet en ålder och objektets attribut för att lagra sin ålder är en int, är det lämpligt att ta emot en int som inparameter.
Inne i metoden förekommer det något som är nytt. Det reserverade ordet this, vilket betyder "det här objektet". Jag har gjort det lite lurigt för Er i denna metod. Jag har döpt både inparametern och klassens attribut för att lagra ålder till age. Oj, oj, oj...vilket misstag! "age = age", vaddå inparametern är lika med inparametern eller?
Det är nu vi har nytta av det reserverade ordet this. Inparametern är en s.k. lokal variabel. En lokal variabel existerar endast i dess scope. Med scope menar jag det område som den tillhör och kan vara åtkomlig att jobba med.
Inparametern "skapas" i metodens huvud och existerar därför endast från det att metoden startar till det att metoden slutar. Anger vi this följt av punkt så kan vi komma åt objektets alla attribut och metoder. Nu när vi "olyckligt" har döpt attributet och inparametern till samma sak kan vi särskilja dem åt genom att säga: "det här objektets attribut age ska tilldelas värdet av inparametern age".
Krångligt? Jo, lite kanske, men det släpper när Ni blir vana....
Glöm inte den startande måsvingen och den avslutande måsvingen för metoden.
Den fullständiga koden bör se ut så här:
class Human {
int age;
String name;
int myAge() {
return age;
}
String myName() {
return name;
}
// Metod som ger objektet dess ålder
void setAge(int age) {
this.age = age;
}
// Metod som ger objektets dess namn
void setName(String name) {
this.name = name;
}
}
En variant!
Självklart skulle man kunna göra det lättare för sig genom att inte döpa inparametrar och klassens attribut till samma sak enligt följande:
class Human {
String name;
// Tidigare kod
// Lite smidigare sätt kanske(?)
void setName(String tmpName) {
name = tmpName;
}
}
Så, ska vi skapa lite "nya människor" ???
Skapa nya objekt
Vi har tidigare skapat objekt av klassen String med det reserverade ordet new enligt följande kod:
String text = new String("Hejsan!");
Jag tänkte att vi skulle göra något liknande med vår klass Human och anropa objektets metoder. Jag tycker att vi skapar en klass som vi kan starta igång som vi sen använder för att skapa några nya objekt av klassen Human.
Startklass
class SkapaObjekt {
public static void main(String[] args) {
// Skapa ett Human-objekt
Human human1 = new Human();
}
}
Ok, då ska vi kort gå igenom kodsatsen.
Först angav vi vilket klass vi vill skapa objekt utav, Human. Sedan skrev vi ett namn vad vi vill kalla den variabel som "håller" vårat objekt som vi ska skapa, human1. Denna variabel är mera känd som en objektreferens. D.v.s. det är en variabel som håller ett utrymme i minnet (en referens) till vart objektet befinner sig.
Sedan så tilldelar vi denna variabel (objektreferensen) ett nytt objekt av klassen Human. Inte så komplicerat va?!
Då provar vi att ge vårat objekt en ålder och ett namn:
class SkapaObjekt {
public static void main(String[] args) {
// Skapa ett Human-objekt
Human human1 = new Human();
// Ge objektet en ålder
human1.setAge(35);
// Ge objektet ett namn
human1.setName("Andreas Eriksson");
}
}
Vi ser att när man vill anropa en metod hos ett objekt i Java så skriver man först objektreferensen (human1) följt av en punkt och sedan metodens namn. Inte svårare än så...
Ska vi be vårat objekt att berätta hur gammal den är och vad den heter? Ok, se följande kod:
class SkapaObjekt {
public static void main(String[] args) {
// Skapa ett Human-objekt
Human human1 = new Human();
// Ge objektet en ålder
human1.setAge(35);
// Ge objektet ett namn
human1.setName("Andreas Eriksson");
// Fråga och skriv ut objektets ålder
System.out.println("Objektets ålder: " + human1.myAge());
// Fråga och skriv ut objektets namn
System.out.println("Objektets namn: " + human1.myName());
}
}
En liten förklaring av det sista två kodsatserna.
System.out.println("Här skriver man text som man vill skriva ut i kommandotolken (MS-DOS fönstret)");
Ovanstående kodsats skriver som sagt ut text till kommandotolkens (MS-DOS fönstret). Det vi har gjort är att kombinera denna operation med att skriva ut information från objektet.
Vi vet att human1.myAge() returnerar en int (ett heltal), så vi konkatinerar (slår ihop) detta tal med strängen vi vill skriva ut i kodsatsen (konkatinering av strängar i Java görs med ett +-tecken):
System.out.println("Objektets ålder: " + human1.myAge());
Samma sak gäller för kodsatsen för att skriva ut objektets namn.
Nu tycker jag att vi kompilerar filen...
Info!
I Java om man vill kompilera flera källfiler samtidigt kan man använda sig av * som "wildcard".
...och kör igång den.
Ni borde få följande resultat:
Att man får konstiga tecken för å, ä, och ö i kommandotolken (MS-DOS fönstret) ibland beror på teckentabellen som just nu används i operativsystemet och har inget med Java att göra.
Konstruktor
När man skapar ett nytt objekt av en klass anropas automatiskt en s.k. konstruktor för objektet. En konstruktor är en sorts metod som man vanligtvis gör de initieringar, av t.ex. attribut, man behöver för det nya objektet vid start. Det är vanligt att man i konstruktorn anropar metoder som strukturerar upp knappar, menyer etc. i en klass som ska representera ett GUI (Graphical User Interface).
En konstruktor har alltid samma namn som den klass den finns i. Konstruktorer kan ta inga (parameterlös), en eller flera inparametrar av valfri datatyp eller objekt. Konstruktorer kan inte ha någon returtyp , inte ens void.
Om ingen konstruktor definieras i klassen av programmeraren så skapas en parameterlös konstruktor (som inget gör) automatiskt av Javakompilatorn. Den parameterlösa konstruktorn brukar kallas för en default konstruktor.
class EnKlass {
// Default konstruktor
EnKlass() {
}
}
Man kan ha flera konstruktorer i sin klass så länge de har olika antal inparametrar eller olika datatyper på sina inparametrar.
class AnnanKlass {
// Default konstruktor
AnnanKlass() {
}
// Konstruktor som tar inparameter av typ String
AnnanKlass(String text) {
}
// Konstruktor som tar inparameter av typ int
AnnanKlass(int siffra) {
}
// Konstruktor som tar inparameter av typ String och int
AnnanKlass(String text, int siffra) {
}
// Och så vidare...
}
Om man skapar egna konstruktorer i en klass, måste man själv definiera den parameterlösa konstruktorn om man vill ha en sådan.
Man kan också anropa andra konstruktorer innefrån den man just nu är i. För detta använder man det reserverade ordet this. Detta kan vara en teknik för att initiera ett default värde till ett attribut om den parameterlösa konstruktorn anropas.
class Human {
// Attribut som representerar detta objekts ålder
int age;
// Default konstruktor
Human() {
this(0); // Anropar koonstruktorn som tar en inparameter av typen int
}
// Konstruktor som tar ett heltal som inparameter
Human(int age) {
this.age = age; // Initierar attributet age med ett värde
}
}
Som vi ser i ovanstående kod så anropas konstruktorn som tar en inparameter av typen int från default konstruktorn med hjälp av det reserverade ordet this. Så när du skapar ett nytt objekt av klassen Human med koden:
Human human1 = new Human();
, så initieras dess ålder till 0 (noll).
Så, en liten summering av konstruktorer
- Har samma namn som klassen.
- Får inte ha returtyp (inte ens void).
- Får finnas flera, men då måste de ha olika antal inparametrar eller olika datatyper på inparametrarna.
- Om man inte definierar några egna konstruktorer, så definieras automatiskt en parameterlös konstruktor som inget gör.
- Om man definierar egna konstruktorer, måste man själv definiera den parametrlösa konstruktorn om man vill ha den.
- En konstruktor kan anropa en annan konstruktor med koden: this(argument);
- En konstruktor kan bara bli anropad endast en gång.
Det var allt jag tänkte gå igenom om konstruktorer...
Summering
Oj, oj, oj!!! Idag blev det mycket. Jag ska försöka att hålla nere storleken av artiklarna i fortsättningen, men det kändes som att dessa saker var bra att ta tillsammans.
Efter att Ni har läst denna artikel ska Ni ha kunskap om hur man skriver metoder i Java, skapar objekt och anropar metoder hos dessa objekt. Ni har också fått en bild av vad en konstruktor är för något och en del lämpliga användningsområden för denna.
I nästa artikel ska vi tala lite om paket i Java och åtkomstmodifierare.
Referenser
Skansholm, J. (1999). Java Direkt (2:a rev. Uppl.). Lund: Studentlitteratur.
Om skribenten…
Andreas Eriksson arbetar idag som frilandskonsult med bl.a. distribuerad programmering och systemutveckling i Java. Han har tidigare föreläst på bl.a. Högskolan i Gävle inom objektorienterad databasutveckling med språket Java som verktyg.
Han har mångårig erfarenhet av utveckling i Java och är sedan 2002 Sun Certified Java Developer for the Java 2 Platform.
Maila mig gärna för kommentarer.
Mark Lomnäs
Hej! Ber att få tacka för en bra och tydlig beskrivning av detta med konstruktor och dess funktion. Finns mycket på nätet men allt är inte tydligt och konkret. Mvh