Lektion 2
Datateknik A, Java I, 5 poäng
Syfte:
Att förstå vad klasser och objekt är. Hur vi skriver
egna enkla klasser för att sen skapa objekt av dessa.
Prova på att använda metoder för att manipulera data i
ett objekt. Lära sig att använda olika metoder för att läsa
in data från tangentbordet.
Att läsa:
Kursboken, Kapitel 2 (sida 51 – 74)
http://java.sun.com/docs/books/tutorial/java/concepts/object.html
http://java.sun.com/docs/books/tutorial/java/concepts/message.html
http://java.sun.com/docs/books/tutorial/java/concepts/class.html
http://java.sun.com/docs/books/tutorial/java/data/objects.html
Lektion 2
Java I, 5 poäng
Vi ska i denna lektion fortsätta med vår översikt över Javaspråket. Vi kommer sen att
gå in på det mest centrala i språket, nämligen klasser och objekt.
Robert Jonsson
ITM Östersund
Sida 1
Lektion 2
Java I, 5 poäng
I förra lektionen nämnde vi att det i Java följer med ett antal klassbibliotek
(standardbibliotek) eller paket. Paket är en modulariseringsmekanism som används
för att gruppera ihop klasser som ”hör samman” med varandra.
Samtliga standarbibliotek ligger i olika paket och har namn som java.lang (klasser
för de mest grundläggande funktioner i Javaspråket), java.util (stödklasser för
stack, hashtabell, datum, tid etc.), java.io (klasser för fil och I/O-hantering),
java.net (klasser för nätverkskommunikation och Internetklasser), java.awt (klasser
för användargränssnitt).
En utvecklare kan också skapa egna klassbibliotek och lägga in dem i paket. Paket
lagras i en katalogstruktur baserad på ett pakets namn.
När klasser från ett paket ska användas måste klasserna importeras från paketet
genom en import-sats. Antingen kan alla klasser i paketet importeras, eller så kan
endast de klasser som verkligen ska användas importeras. En import görs med
nyckelordet import följt av namnet på paketet (och eventuellt klassen).
Speciella synlighetsregler finns som bestämmer vad som ska vara åtkomligt inom och
utanför ett paket. Man kan alltså mer eller mindre bestämma vilka som ska kunna
använda klasserna i paketet (tolka inte vilka som vilka olika användare).
Robert Jonsson
ITM Östersund
Sida 2
Lektion 2
Java I, 5 poäng
Som vi nämnde i förra lektionen kan ett Javaprogram delas upp i två olika kategorier: applikationer och
pplets. Vi kommer i denna kurs inte att titta speciellt mycket på Applets utan endast nämna vad det är.
En Java applet har inte någon main-metod utan har istället en uppsättning metoder som webbläsaren
kommer att anropa (metoderna har namn som init, destroy, start och stop som antyder när metoderna
anropas).
En Java applet har ett utseende som visas på den yta som den tilldelats av webbläsaren. Utseendet på
denna yta definieras av appletens paint-metod, som innehåller anrop som grafiskt ritar upp ytans
utseende.
Programmet i bilden ovan, FirstApplet, importerar klasser från två andra paket, java.applet som
innehåller klassen Applet och java.awt som innehåller Javas gränssnittsklasser (bl.a. grafikklasser).
Klassen i programmet heter FisrtApplet (och sparas m.a.o. i en fil med namnet FirstApplet.java) och
ärver en klass Applet (ett arv uttrycks genom nyckelordet extends följt av namnet på den klass som
ärvs). Mer om arv senare.
Den enda metod som klassen har är metoden paint, som bestämmer innehållet i appletens yta.
Till metoden kommer ett objekt av typen Graphics att skickas och genom att anropa metoder på detta
objekt bestäms utseende på den yta appleten ”äger”.
Metoden drawString() tar tre s.k. argument. Det första är den text som ska skrivas ut, de två andra är på
vilken x- respektive y-koordinat texten ska skrivas ut på (den yta vi ritar på har koordinaterna (0, 0) i
övre vänstra hörnet).
Metoden drawLine ritar ut en linje mellan en start- och slut koordinat. I det här fallet från (0, 0) till
(100,100).
Utöver dessa finns det mängder med andra metoder vi kan anropa. T.ex. för att byta färg, rita cirklar
m.m.
För att ta reda på vilka metoder som går att anropa kan man titta i Javas API. Leta efter klassen
Graphics så ser du att det finns mängder med ”rit-funktioner”.
I exemplen som följer med lektionen finns filen FirstApplet.java. Prova att kompilera den med javac
och därefter köra den med java för att se vad som händer (felmeddelande).
Robert Jonsson
ITM Östersund
Sida 3
Lektion 2
Java I, 5 poäng
För att starta en applet krävs ett html-dokument där vi anger vilken klass (Applet) som
ska köras, vi kan inte direkt köra .class-filen. Det minsta antalet s.k. html-taggar som
krävs för att visa en applet är <html> och <applet>. I applet-taggen specificerar
vi vilken klass vi vill köra samt vilken bredd och höjd vi tilldelar vår Applet. Det är
denna yta som används för att rita upp innehållet.
En Applet testas antingen genom en s.k. appletviewer i en utvecklingsmiljö, eller
genom att de refereras i en HTML-sida som sedan läses in i en webbläsare. Observera
att det är html-sidan som ska köras och inte class-filen.
Bland exemplen till lektionen finner du filen FirstApplet.html. Prova att öppna den i
en webbläsare. Du kan även prova på att använda appletviewer. Öppna ett
kommandofönster och ställ dig i den katalog där html-filen ligger. Skriv sen:
appletviewer FirstApplet.html
Observera att html-sidan inte behöver ha samma namn som vår Applet.
Robert Jonsson
ITM Östersund
Sida 4
Lektion 2
Java I, 5 poäng
Appletviewern kan sägas vara en ”minimal” webbläsare för att testa Applets. Den
startas med namnet på en HTML-fil och kommer sedan att läsa denna fil och starta ett
fönster med den applet som refereras i HTML-filen.
Via menyer kan sedan denna Applet stoppas, startas om, parametrar och annan
information avläsas.
En viktig varning i samband med exekvering av en applet i en appletviewer är att
appleten inte exekveras med de säkerhetskontroller som utförs när samma Applet
exekverar i en riktig webbläsare.
Exempelvis kan en Applet som exekveras i appletviewer läsa och skriva filer på den
lokala hårddisken vilket inte en applet som exekveras i en webbläsare får/kan göra.
Robert Jonsson
ITM Östersund
Sida 5
Lektion 2
Java I, 5 poäng
I stort sett alltid så måste program ha indata av något slag som programmet ska
bearbeta. Hittills i våra program har vi endast behandlat utdata med hjälp av
System.out.println. När ett program behöver indata av någon form är det
vanligtvis användaren som får mata in data från tangentbordet. Det kan t.ex. ske
genom att mata in text i olika textfält. De två sätt vi kommer att jobba med i denna
kurs är genom att mata in text direkt från kommandofönstret och genom dialogrutor.
Oavsett vilket sätt vi använder oss av så är det en komplicerad process. Att exakt
förklara hur koden som används fungerar är något som vi inte klarar av med vad vi
hittills gått igenom. Detta är ytterligare exempel på kod som ni får acceptera som den
är.
Det första alternativet är genom att använda ett objekt av klassen BufferedReader
som läser de tecken som matas in från tangentbordet. All in- och utmatning (I/O) i
Java kan generera fel av något slag, så när vi använder denna metod måste vi antingen
fånga felet (catch) eller kasta det vidare (throw). Detta är exempel på s.k.
felhantering som vi inte kommer att gå igenom i denna kurs.
Med hjälp av identifieraren input kan vi nu läsa in det användaren skriver på
tangentbordet till programmet. Detta gör vi genom att anropa metoden readLine().
Resultatet sparar vi i en sträng som vi ger namnet svar.
Ta en titt på exemplet Input1.java för att testa inmatning med BufferedReader från
kommandofönstret.
Robert Jonsson
ITM Östersund
Sida 6
Lektion 2
Java I, 5 poäng
Det andra alternativet är att använda klassen JOptionPane för att visa grafiska dialogrutor där
användaren kan göra sina inmatningar. Med JOptionPane kan vi även skriva ut ett resultat i en
dialogruta, istället för att skriva ut det på skärmen med System.out.println.
I klassen JOptionPane finns det ett antal fördefinierade dialogrutor vi kan använda i vårt program. En
av dessa kommer vi åt genom att anropa metoden showMessageDialog() på klassen JOptionPane.
Denna metod kräver två argument (indata). Det första är var på skärmen dialogrutan ska visas. Här
anger vi null vilket innebär att rutan kommer att centreras på skärmen. Det andra argumentet anger
vilken text som ska visas i dialogrutan.
Ex) JOptionPane.showMessageDialog(null, "Snart är det julafton");
Med en annan fördefinierad dialogruta kan vi låta användaren mata in text från tangentbordet som vi
sen kan använda i programmet. Denna dialogruta kommer vi åt genom att anropa metoden
showInputDialog(), också i klassen JOptionPane. Denna metod tar ett argument, vilket är en
sträng med den text som ska visas i dialogrutan (frågan/uppmaningen till användaren).
När användaren har skrivit in sin text och tryckt på knappen Ok (eller trycker enter) returneras det
inskrivna som vi kan ta emot och lagra i en sträng.
Ex)String svar = JOptionPane.showInputDialog("Vilken veckodag är det?");
När vi har ett program med ett grafiskt användargränssnitt är det viktigt att vi avslutar programmet
genom att skriva System.exit(0); Argumentet 0 till metoden exit anger att programmet
avslutades på ett korrekt sätt. Detta värde returneras till kommandopromten varifrån vi startade
applikationen. Om vi vill kan vi ange olika felkoder istället för 0 om något fel har inträffat i
programmet.
Ta en titt på programmet Input2.java i exemplen för att se hur dialogrutor kan användas för in- och
utmatning av data.
Robert Jonsson
ITM Östersund
Sida 7
Lektion 2
Java I, 5 poäng
Vi kommer nu att titta lite närmare på hur kompileringsprocessen i Java fungerar och
hur den virtuella Javamaskinen jobbar. Java har, som du i det här laget redan vet, en
mycket enkel struktur på sina filer där endast två filtyper används.
En källkodsfil som innehåller en Javaklass måste ha samma namn som klassen följd
av suffixet ”.java”. Utifrån denna källkodsfil genereras vid kompileringen en fil med
bytekod som har samma namn som klassen följt av suffixet ”.class”.
Eftersom klasser läses in dynamiskt under programmets exekvering och ingen
länkning sker så behövs inga s.k. objekt-filer som länkas ihop till exekverbara filer.
Endast två filer behövs, ”.java”- och ”.class”-filer.
Fig.
Endast ”.java”-filer med källkod och ”.class”-filer med bytekod behövs i Java. Den
virtuella Javamaskinen startas med namnet på en klass och läser sedan in ytterligare
klassers bytekod-filer allteftersom behov uppstår.
Robert Jonsson
ITM Östersund
Sida 8
Lektion 2
Java I, 5 poäng
Den virtuella Javamaskinen är den komponent som läser, tolkar och exekverar
bytekod.
Normalt är denna komponent skrivet för den aktuella plattformen (operativsystem och
hårdvaruarkitektur) och som läser bytekoden, tolkar den, och gör anrop mot det
underliggande operativsystemet.
Den virtuella maskinen är alltså i högsta grad plattformsspecifik och måste skaffas om
den inte redan finns inbyggd i aktuell plattform (i en del webbläsare finns en virtuell
Javamaskin inbyggd).
Robert Jonsson
ITM Östersund
Sida 9
Lektion 2
Java I, 5 poäng
Specifikationen av den virtuella maskinen och formatet på bytekoden är mycket lik en
”virtuell” processor så den virtuella maskinen upprätthåller begrepp som programräknare, stack, cache etc.
Den enda skillnaden är att den virtuella maskinen exekveras som ett program.
Både specifikationen av formatet på bytekoden och den virtuella maskinen är helt
öppen, och det är teoretiskt möjligt att skriva en bytekod-kompilator för ett annat
språk än Java, men detta har visat sig svårare än många trott.
Den virtuella Javamaskinen laddar dynamiskt in ”.class”-filer allt eftersom de behövs
i programmet. För att exekvera en applikation anges namnet på den på en klass, varpå
dess ”.class”-fil med bytekod läses in och dess main-metod exekveras av den virtuella
maskinen. Allteftersom nya klasser refereras i applikationen kommer de att läsas in
dynamiskt (allt eftersom).
När en ”.class”-fil (Applet) läses från Interner så kommer koden i filen först att passas
till en verifierare. Verifieraren är en speciell modul som går igenom filen och
konstaterar att koden är ”riktig” och att inga farliga operationer utförs i koden (som att
läsa filer på användarens dator).
Det finns i JDK (den utvecklingsmiljö vi använder i kursen) ett program, javap, som
är en disassembler av bytekod och som visar bytekoden på ett för människor läsbart
format. Detta program kan tillsammans med specifikationen av den virtuella
maskinen rent teoretiskt användas för att lära sig bytekod-formatet (varför man nu
skulle vilja det?). Observera att man med javap INTE får tillbaka den källkod som
finns i java-filen.
Prova gärna att använda javap på någon av de class-filer du gjort för att se vad som
händer.
Robert Jonsson
ITM Östersund
Sida 10
Lektion 2
Java I, 5 poäng
En av de vanligaste invändningarna mot Java är att program skrivna i Java har dåliga
prestanda. Invändningarna har varit och är fortfarande i vissa fall berättigad. Och det
är naturligtvis arrangemanget med en virtuell maskin som i huvudsak skapar dessa
prestandakostnader. Den virtuella maskinen kan ju ses som en interpretator som
lägger ett extra skal över den slutliga exekveringsmiljön. Språket Java som sådant har
inga konstruktioner som gör att det skulle vara långsammare än andra språk.
Att uppnå högre prestanda i ett program, oavsett språk eller miljö, kan angripas på
flera olika sätt:
Hög nivå: genom att förbättra sin design och använda mer effektiva datastrukturer
och algoritmer. Ofta kan betydande prestandavinster uppnås genom detta, eftersom
dålig grunddesign nästan alltid leder till program som är långsamma.
Mellannivå: genom att använda diverse ”tricks” på språknivån som att deklarera
variabler som konstanta (static), klasser och metoder som inte får ärvas eller
omdefinieras (final), skapa få och stora klasser. Eller genom att använda shiftoperatorerna vid multiplicering och division.
Låg nivå: genom att se till att den genererade koden kan optimeras och exekveras
snabbare, d.v.s. att den fysiska exekveringen av programmet utförs snabbare på den
aktuella plattformen.
De nivåer som rekommenderas i första hand är den höga och den låga. Att använda
tekniken på mellannivån bryter mot grundläggande principer för god programmering,
och ger program som är svåra att underhålla, som inte är lika utbyggbara och
förändringsbara.
Robert Jonsson
ITM Östersund
Sida 11
Lektion 2
Java I, 5 poäng
Vi ska nu titta på hur Java fått bättre prestanda genom att på låg-nivå förändra hur
Javaprogram exekveras.
En Just-In-Time (JIT) kompilator är en kompilator som översätter bytekod till
plattformsspecifik kod som sedan exekveras på aktuell plattform (likt en kompilator
av exempelvis C++).
Kompileringen görs dock dynamiskt vid exekvering av ett program, där JITkompilatorn kopplas på den virtuella Javamaskinen. Det är alltså bytekoden som
kompileras, ej den ursprungliga Javakällkoden.
Den virtuella Javamaskinen är inte medveten om JIT-kompilatorn, och dess valiga
säkerhetskontroller av bytekoden kommer fortfarande att utföras.
JIT har diverse tricks för sig för att snabba upp exekveringen. Bl.a. kommer den att
spara genererad kod för metoder så att själva översättningen från bytekod till
plattformsspecifikkod endast sker en gång. Den gör enkla former av optimering av
den genererade koden. Den kan tyvärr inte göra mer avancerad optimering eftersom
den helt enkelt inte har tid – översättningen sker ju i samband med att koden ska
exekveras (just in time).
Mätningar har påvisat stora effekter på exekvering av Javaprogram. Exakta måtten
varierar, men alltifrån:
3-4 ggr snabbare när användargränssnittskod exekveras
till 40-50 ggr snabbare för beräkningar, loopar och upprepade metodanrop.
Robert Jonsson
ITM Östersund
Sida 12
Lektion 2
Java I, 5 poäng
Ingenting förhindrar att Javakod kompileras direkt till plattformsspecifik kod, d.v.s.
att källkoden kompileras till en exekverbar fil på aktuell plattform (i Windows en exefil.
Olika leverantörer av utvecklingsmiljöer som exempelvis Symantech har också
lanserat sådana kompilatorer. En utvecklare kan då välja att antingen få bytekod
genererad eller att få en plattformsspecifik exekverbar fil.
Med en ren kompilator kan också mer avancerad optimering göras eftersom denna
optimering då görs i samband med kompileringen, och det finns då hur mycket tid
som helst till detta. Vissa hävdar att sådana kompilatorer ger program med
jämbördiga prestanda som exempelvis kompilerad C++ kod.
Sun avråder dock kraftigt mot denna lösning eftersom det bryter mot Javas
plattformsoberoende.
Robert Jonsson
ITM Östersund
Sida 13
Lektion 2
Java I, 5 poäng
HotSpot är en ny teknik för att implementera virtuella maskiner som bygger på något
som kallas adaptiv optimering.
Den virtuella maskinen analyserar varje Javaprogram när den exekverar, och
använder denna information till att omedelbart optimera de kritiska s.k. ”hot spots”
som ett program har (de områden i programmet där de största datorresurserna
förbrukas). Genom att optimera endast dessa kritiska områden frigörs tid att göra mer
avancerade optimeringar.
Med adaptiv optimering kan bättre optimeringar göras än med en ”ren” kompilator,
eftersom mer information finns om programmets exekvering (en ”ren” kompilator
studerar endast källkoden före programmets exekvering).
Sun påstår att i och med HotSpot kommer Javaprogram inte att ha någon
prestandakostnad alls jämfört med plattformsspecifika program. Vilket vi dock ska ta
med en nypa salt.
Robert Jonsson
ITM Östersund
Sida 14
Lektion 2
Java I, 5 poäng
För att kort sammanfatta det hela så:
Javaspråkets grundblock är klasser som beskriver egendefinierade ”typer” och objekt
(förekomster) av dessa klasser. En klass beskrivs i termer av instansvariabler
(datavariabler) och metoder. En klass beskrivs i en ”.java”-fil med samma namn som
klassen.
Java har också en mängd fördefinierade primitiva typer som int, long, char,
boolean, float och double. För dessa datatyper finns olika typer av operatorer som
exempelvis aritmetiska, jämförelse, booleska, bit, skift och tilldelningsoperatorer.
Exekveringsflödet i ett Javaprogram styrs av kontrollflödeskonstruktioner, som kan
vara antingen villkor (if-else, switch), iteration (while, do-while, for) eller avbrott
(break, continue och return).
Till Javaspråket hör ett stort antal klasser organiserade i bibliotek eller paket med
klasser. Detta är klasser som utvidgar själva språket, stödklasser för datastrukturer, filoch I/O-hantering, nätverkskommunikation och Internet, Applets och
användargränssnitt.
Den virtuella Javamaskinen är ett plattformsspecifikt program som läser kompilerad
bytekod och exekverar den på aktuell plattform. För att uppnå maximal prestanda kan
olika kompileringstekniker tillämpas.
Just-In-Time kompilator som översätter Javabytekoden ”i flykten” till maskinkod på
aktuell plattform.
Det finns också rena kompilatorer som kompilerar Javakällkod (eller bytekod) till en
exekverbar fil för aktuell plattform.
Den senaste tekniken är en s.k. ”HotSpot” virtuell maskin som utför adaptiv
optimering av koden under exekveringen av programmet. Det optimerar enbart de
kritiska ställena i koden, vilket medför att mer avancerad optimering kan utföras.
Robert Jonsson
ITM Östersund
Sida 15
Lektion 2
Java I, 5 poäng
Vi börjar nu titta på det mest väsentliga i ett objektorienterat språk som Java nämligen
klasser.
Som nämnts beskriver en klass en objekttyp, d.v.s. hur objekt av klassen ska
representeras och vilka metoder de ska stödja.
En klass beskriver objektens egenskaper och beteende, d.v.s. vilka instansvariabler
och metoder objektet har. Instansvariabler används för att lagra information om
objektet och metoderna används för att behandla denna information.
När klassen väl är skriven fungerar den som en ritning för de objekt som ska skapas
av klassen. Utifrån klassbeskrivningen skapas sen olika objekt. Man brukar säga att
man skapar instanser (förekomster) av klassen, objekten instansieras.
Robert Jonsson
ITM Östersund
Sida 16
Lektion 2
Java I, 5 poäng
En klass börjar alltid med en klassdeklaration, vilken i sin tur börjar med nyckel ordet
class följt av namnet på klassen. Vi har redan nu provat på att skapa ett flertal olika
klasser och alla har börjat med en klassdeklaration.
Därefter ramas klassens innehåll in med en påbörjande vänsterklammer { och en
avslutande högerklammer }.
Det som ingår i klassen kallas för medlemmar, och en medlem kan antingen vara ett
instansvariabel eller en metod. Hittills har våra klasser endast innehållit en enda
medlem, metoden main().
En klassdeklaration kan också innehålla en specifikation om klassen ska ärva en
annan klass och ha speciella modifierare för att ge klassen andra speciella egenskaper.
Robert Jonsson
ITM Östersund
Sida 17
Lektion 2
Java I, 5 poäng
Vi ska nu testa på att skriva en första klass enligt specifikationen ovan. Det brukar
vara vanligt att med UML visa hur klassens specifikation ser ut (vilka instansvariabler
och metoder den innehåller). Enligt beskrivningen ska klassen representera en punkt
och namnet på klassen väljs lämpligen till Punkt (alla klasser ska ha STOR första
bokstav i varje ord). I ett s.k. klassdiagram (UML) placerar vi namnet på klassen
överst.
För att kunna lagra information om punktens koordinater behöver vi två variabler.
Eftersom dessa tillhör klassen blir det klassens instansvariabler. Vi döper dem till
xkord respektive ykord och väljer datatypen int (heltal).
Vi ska kunna sätta nya värden på koordinaterna och måste då ha metoder för detta
(instansvariablerna används för att lagra information om objektet och metoderna
används för att behandla denna information). Vi behöver därför metoderna setx()
och sety(). För att kunna skriva ut koordinaterna använder vi metoden print().
Observera att namnen på instansvariablerna och metoderna hade kunnat väljas till
något annat.
Vi har nu klart för oss hur klassen ska se ut. Återstår nu ”bara” att skriva koden.
Robert Jonsson
ITM Östersund
Sida 18
Lektion 2
Java I, 5 poäng
I denna klass finns det nu fem medlemmar: medlemsmetoderna setX(), setY()
och print(), samt instansvariablerna xkord och ykord.
Ordningen på medlemmarna spelar ingen roll, de hade kunnat stå i en annan ordning.
Vi hade till exempel kunnat börja med att skriva medlemsmetoden setX() och
därefter våra instansvariabler. Det viktiga är att vi skriver dem inom
klassdeklarationen. Dock är det vanligt att samla alla instansvariabler överst och
därefter metoderna.
På de följande sidorna tittar vi närmare på de olika delarna i klassen.
Robert Jonsson
ITM Östersund
Sida 19
Lektion 2
Java I, 5 poäng
Varje klass börjar som vi redan nämnt med en klassdeklaration. Klassdeklarationen
ger klassens dess namn, samt specificerar hur klassen kan användas, t.ex. vilka andra
klasser/objket som kommer att få tillgång till klassen och om klassen i fråga ärver
egenskaper från någon annan klass.
En klassdeklaration består av en eller flera åtkomstmodifierare, därefter nyckelordet
class, följt av det namn du vill ge din klass. Sist kan man ange om man vill att
klassen ska ärva eller implementera någon annan klass.
Både klassmodifierare och eventuella arv behöver inte anges. Om de utesluts kommer
Java att använda default-värden. Java kommer då att begränsa tillgången till klassen
något samt att låta den ärva från klassen Object (som är en Superklass till alla
klasser i Java).
Det normala är att använda public som åtkomstmodifierare för klasser. Detta
innebär att vilka andra klasser som helst kan skapa ett objekt av klassen. Observera att
vi aldrig kan använda åtkomstmodifieraren private i en klassdeklaration.
I exemplen har jag skrivit en klass, Privat.java, där jag använd private i
klassdeklarationen. Prova att kompilera och köra denna klass för att se vad som
händer.
Robert Jonsson
ITM Östersund
Sida 20
Lektion 2
Java I, 5 poäng
En instansvariabel är en datavariabel som lagras i ett objekt. Samtliga instansvariabler
i ett objekt representerar tillsammans objektets information. En person kan t.ex.
representeras med instansvariabler för personens namn, ålder och personnummer och
en punkt kan representeras med x- och y-koordinat.
I objektorienterad programmering försöker man kapsla in ett objekts information och
göra det ”osynligt” för andra. Därför används normalt åtkomstmodifieraren private
för instansvariabler. Detta innebär att inga andra klasser kan få en direkt åtkomst till
det värde som finns lagrat i en instansvariabel. Det är endast den egna klassen som
kan komma åt de värden som finns lagrade i instansvariabler.
Om andra klasser behöver tillgång till vissa instansvariabler är det bättre att
tillhandahålla speciella set- och get-metoder än att deklarera instansvariabler som
publikt (därför har vi i klassen Punkt satt private för instansvariablerna för att
”gömma” information om koordinaterna från andra klasser, men har publika set()metoder för att ändra värdet på instansvariablerna).
Instansvariablerna behöver inte deklareras på något speciellt ställe utan kan stå före,
mellan eller efter metoderna. Men normalt samlar man alla instansvariabler på ett och
samma ställe för att göra koden mer lätt läst (och då vanligtvis överst i koden direkt
efter/under klassdeklarationen).
Robert Jonsson
ITM Östersund
Sida 21
Lektion 2
Java I, 5 poäng
I vårt exempel deklareras två instansvariabler, xkord och ykord. Deklarationerna
består av en åtkomstmodifierare (private), en datatyp (int), samt ett namn
(xkord).
Åtkomstmodifieraren specificerar om objekt av andra klasser ska ha tillgång till denna
medlem. I detta fall är instansvariabeln deklarerat som privat och är därför inte
tillgänglig för objekt av andra klasser.
Datatypen specificerar vilka värden som kan lagras i instansvariabeln och vilka
operationer som kan utföras på den. xkord och ykord är av typen int, som endast
kan lagra heltal.
Instansvariabelnamnet är det namn vi döper typen till. Det är detta namn vi sen
använder för att referera eller identifiera vår variabel med, och som vi använder för att
utföra operationerna med.
Som datatyp kan anges primitiva typer som int, char, double, men också namn
på andra klasser som Punkt.
Robert Jonsson
ITM Östersund
Sida 22
Lektion 2
Java I, 5 poäng
Metoderna i en klass beskriver de tjänster som klassen tillhandahåller. Metoderna är
den del i en klass som innehåller den aktiva delen (där något egentligt arbete utförs).
Metoder innehåller den kod som verkligen utför någonting. All aktiv kod som
exekveras finns i metoder i klassen.
Det finns inget sätt att deklarera metoder utanför en klass (som t.ex. i C++). Att utföra
den kod som finns i en metod sker via s.k. metodanrop.
Metoder är de delar i en klass som innehåller exekverbara satser.
En metod är ett namngivet block av kod som utför en viss uppgift.
Genom att associera ett namn till metoden kan detta namn användas för att exekvera
satserna i metoden via s.k. metodanrop.
De klasser vi hittills har skrivit har endast innehållit main()-metoden. Denna kan inte
anropas av andra klasser utan anropas av den virtuella maskinen när klassen först
startas.
Robert Jonsson
ITM Östersund
Sida 23
Lektion 2
Java I, 5 poäng
Vår exempelklass (Punkt) har tre metoder: setX() setY() och print().
En metod definieras med en eller flera modifierare. Normalt deklareras alltid en metod som public
eftersom vi vill att andra klasser (objekt) ska kunna anropa metoden för att exekvera den kod som finns
skriven där. T.ex. vill vi att andra klasser ska kunna anropa setx()och setY() för att kunna ändra
punktens koordinater, eller print() för att kunna skriva ut information om punkten.
Alla metoder har en returtyp som anger vad som returneras från metoden när alla kod i den har
exekverats. Som returtyp kan man ange någon av de primitiva datatyperna (int, char, double etc),
men man kan även returnera andra objket från en klass. Anger man nyckelordet void returnerar
metoden inget värde. Main()-metoden deklareras alltid som void och den returnerar därför inget.
Namnet på metoden kan man själv välja. Samma regler som för namn på instansvariabler och variabler
gäller när vi namnger en metod. Tillskillnad från klasser där förstabokstaven i varje ord har STOR
bokstav, så har vi liten bokstav på första ordet i metoden. Eventuellt resterande ord i metodnamnet får
STOR bokstav.
En metod kan eventuellt ha en eller flera parametrar, som anges inom parenteser (i vårt fall har
metoden setX en parameter). Parametrar används för att skicka data till den metod som anropas. I vårt
fall ovan måste vi skicka in det nya värdet på x- eller y-koordinaten när metoderna setX eller setY
anropas.
Slutligen kommer kodsatserna för metoden inom matchande klamrar (precis som i fallet med
klassdeklarationen). Definitionen av metoden kan läggas vart som helst inom klassdeklarationen, men
läggs normalt efter deklarationen av instansvariabler.
Vi har nu gått igenom alla deklarationer i klassen (dock inte den kod metoderna innehåller). I exemplen
som följer med lektionen finner du klassen Punkt.java. Prova att kompilera och köra den. Som du
kommer att se får vi ett felmeddelande när vi kör klassen. Vad är det för felmeddelande och varför får
vi ett fel?
Robert Jonsson
ITM Östersund
Sida 24
Lektion 2
Java I, 5 poäng
Som du märkte när du försökte köra klassen Person så fick du ett felmeddelande.
Anledningen är att klassen saknar en main()-metod och är därför ingen körbar
Javaapplikation. Kom ihåg att alla applikationer i Java måste innehålla en main()metod. För att vi ska kunna använda klassen Person måste vi skapa ett objekt av
klassen.
När klassen är definierad (dess instansvariabler och metoder är skapade) så är det
sedan möjligt att skapa objekt av klassen. Som nämnts så är objekt en instans
(förekomst) av klassen, och fungerar som en variabel av den typ som klassen
definierat.
Ett objekt av klassen kan skapas var som helst i en applikation där klassen är
åtkomligt (inom klassen eller i andra klassers metoder). När objektet är skapat är det
möjligt att referera och använda de metoder och instansvariabler som deklarerats som
tillgängliga (publika) i klassen.
De metoder och instansvariabler som inte deklarerats som tillgängliga är skyddade
och dolda inuti objektet och är inte tillgängliga för andra klasser och objekt.
Robert Jonsson
ITM Östersund
Sida 25
Lektion 2
Java I, 5 poäng
Ett objekt skapas genom att använda operatorn new. Det är endast med new vi kan skapa objekt i Java.
För att skapa ett objekt av klassen Punkt skriver vi:
Punkt p1 = new Punkt();
Här sker både en deklaration och en tilldelning på samma gång. Vi deklarerar variabeln p1 till att vara
av (den egendefinierade) typen Punkt. I p1 kan vi med andra ord lagra objekt som är skapade av
klassen Punkt. Vi tilldelar även variabeln p1 ett nytt objekt av klassen Punkt.
Efter operatorn new skrivs namnet på klassen och inom parenteser eventuella argument till klassens
konstruktormetod (konstruktorn beskrivs senare). new kommer då att skapa ett objekt av angiven klass
genom att reservera utrymme för objektet i minnet och sen initiera det (bl.a. skapa instansvariabler och
eventuellt tilldela dessa värden).
Från new-operatorn returneras sedan en referens till detta objekt. Referensen i exemplet tas emot och
lagras i variabeln p1 (brukar ibland kallas referensvariabel). Se figuren till höger i bilden.
Variabeln p1 är deklarerad att vara av typen Punkt, vilket ska läsas som att den är avsedd att hålla en
referens till ett Punkt-objekt. Via referensen p1 (namnet på variabeln) kommer man åt de
instansvariabler och metoder som det refererade objektet har och som är deklarerad att vara publika.
I Java hanteras objekt alltid via objektreferenser, vilket leder till att man kan höra både termen
”objektet p1” och ”objektreferensen p1” när man talar om variabeln i fråga. Jag kommer att använda
objektet p1 när det pratas om variabler/instansvariabler som är tänkt att lagra ett objekt.
Skillnaden mellan instansvariabler/variabler som lagrar data av en primitiv typ och de som lagrar ett
objekt är att i variabeln för primitiva typer lagras värdet, medan det för ett objekt lagras en referens
(adress till objektet i minnet) till objektet. Observera att detta kan liknas med pekare i C++, men riktigt
så är inte fallet.
Robert Jonsson
ITM Östersund
Sida 26
Lektion 2
Java I, 5 poäng
När objektet skapats är det möjligt att anropa objektets publika metoder. Att anropa en
metod på ett objekt görs genom punktnotation där man skriver objektets namn följt av
en punkt och därefter metodnamnet och metodens eventuella parametervärden (data
som ska skickas till metoden för bearbetning) inom parenteser. Programsatsen
avslutas som alltid med ett semikolon (vilket inte klass- och metoddeklarationer gör).
Det sätt vi kommer att prova de klasser vi skriver i denna kurs är genom att skapa en,
vad jag kallar, testklass. I denna testklass skapar vi ett objekt av den ”riktiga” klassen
och provar att anropa metoder m.m. I UML kan vi ”rita” detta enligt bilden ovan.
Ta nu och öppna klassen PunkTest.java som finns i exemplen. Där provar vi att
skapa objekt av klassen Punkt och anropar dess metoder. Kompilera och kör
klassen.
Det är även möjligt att i klassen Punkt ha en main()-metod och då inte behöva en
testklass. Detta demonstreras i Punkt2.java. Givetvis kan vi från en och samma klass
skapa många objekt. Detta visas i PunktTest2.java.
Robert Jonsson
ITM Östersund
Sida 27
Lektion 2
Java I, 5 poäng
Instansvariabler som deklareras på klassnivå i Java har en räckvidd som sträcker sig
genom hela klassen där den är deklarerad. D.v.s. vi kan i klassens alla metoder
(oavsett om de är publika eller privata) använda klassens instansvariabler.
Jag har hittills enbart deklarerat en instansvariabel, inte tilldelat instansvaribeln något
värde i samband med deklarationen. Vad tror du händer om vi i en metod försöker att
skriva ut värdet på skärmen, innan vi gett instansvariabeln ett värde? Prova att i
PunktTest.java ändra koden så att metoden print() anropas före setX() och
setY(). Vad är det som skrivs ut?
Robert Jonsson
ITM Östersund
Sida 28
Lektion 2
Java I, 5 poäng
I samband med att instansvariablerna deklareras är det också möjligt att tilldela dem
värden.
T.ex:
private inte xkord = 100;
Initieringen av instansvariablerna kommer att göras i samma ordning som de står
uppräknade i klassen, och det är inte tillåtet att i en initiering använda en
instansvariabel som är deklarerat efter den aktuella instansvariabeln.
Alla instansvariabler intitieras innan en eventuell konstruktor körs (mer om
konstruktorn senare).
Om ingen initiering ges kommer primitiva variabler att sättas till värdet 0 och objekt
referenser till att sättas till null. Instansvariabler av typen boolean kommer att
tilldelas värdet false.
Robert Jonsson
ITM Östersund
Sida 29
Lektion 2
Java I, 5 poäng
OBS! Deklarationen av z1 hade inte kunnat stå före deklarationen av x och y!
Robert Jonsson
ITM Östersund
Sida 30
Lektion 2
Java I, 5 poäng
Det finns fyra stycken möjliga åtkomstformer till instansvariabler och metoder:
Publik åtkomst (public)
Skyddad åtkomst (protected)
Privat åtkomst (private)
Och paket åtkomst.
På varje instansvariabel och metod kan åtkomst specificeras genom att som
modifierare använda något av nyckelorden public, protected eller private.
Om ingenting anges erhålls den fjärde formen, paketåtkomst.
Robert Jonsson
ITM Östersund
Sida 31
Lektion 2
Java I, 5 poäng
En medlem (instansvariabel eller metod) som har publik åtkomst är tillgänglig för
”alla”, d.v.s. anropningsbar både inom klassen och för de som skapat objekt av
klassen. Normalt är de flesta metoder publika.
Även klassen kan deklareras med en åtkomstmodifierare. En klass som deklareras
som public är åtkomlig i paket utanför det paket som den är definierad i. Mer om
paket och detta i senare lektioner.
Robert Jonsson
ITM Östersund
Sida 32
Lektion 2
Java I, 5 poäng
Skyddad åtkomst deklareras med modifieraren protected, och innebär att metoden
och/eller instansvariablen:
Är åtkomlig inom klassen, d.v.s. för andra metoder inom klassen.
Är åtkomlig för subklasser, d.v.s. de som ärvt ifrån klassen.
Är åtkomlig för andra metoder inom samma paket som klassen.
Inte är åtkomlig för dem som skapat objekt av klassen.
Robert Jonsson
ITM Östersund
Sida 33
Lektion 2
Java I, 5 poäng
Ett instansvariabel eller metod som är deklarerats som privat är garanterat endast
tillgänglig inom sin egen klass.
De är inte åtkomliga ifrån de som skapat objekt av klassen, inte åtkomliga från
subklasser, och inte åtkomliga från andra klasser inom samma paket.
Normalt bör instansvariabler vara privata eftersom de data som en klass har inte bör
vara synligt utåt, utan bara kommas åt indirekt via klassens metoder. Det kan ibland
också finnas privata metoder som är interna hjälpmetoder för andra (publika) metoder.
Robert Jonsson
ITM Östersund
Sida 34
Lektion 2
Java I, 5 poäng
Om ingen av nyckelorden public, protected, private anges framför en
instansvariabel eller en metod får den som default paketåtkomst. Det finns inget
nyckelord för att uttryckligen ange paketåtkomst. Med paketåtkomst gäller följande
regler för dessa klassmedlemmar:
De är åtkomliga inom det paket i vilken klassen ingår.
De är inte åtkomliga utanför det paket i vilket klassen ingår.
Generellt gäller att man inte bör använda sig av paketåtkomst utan alltid skriva om en
medlem ska vara public, protected eller private.
Robert Jonsson
ITM Östersund
Sida 35
Lektion 2
Java I, 5 poäng
Vi ska nu skapa ytterligare en klass och testklasser. Enligt beskrivningen ovan ska
klassen denna gång representera en person och namnet på klassen väljs därför till
Person.
För att kunna lagra information om personens namn och personnummer behöver vi
två instansvariabler. Vi döper dem till namn och persnr och väljer datatypen
String (sträng eftersom det är text som ska lagras). Instansvariablerna ska vi sätta
till private och i UML-klassdiagram visar vi att åtkomstmodifieraren ska vara private
genom att sätta ett minustecken (-) framför namnet.
Vi ska kunna sätta nya värden på personens namn och personnummer och vi måste
skapa två metoder för detta (instansvariabler används för att lagra information om
objektet och metoderna används för att behandla denna information). Vi behöver
därför metoderna setNamn() och setPersnr(). För att kunna skriva ut
information om personen använder vi återigen en metod med namnet print().
Eftersom vi vill att andra klasser/objekt ska kunna anropa våra metoder måste vi
använda public som åtkomstmodifierare. I UML markerar vi detta genom att sätta ut
ett plustecken (+) framför namnet.
För att se hur koden för denna klass skrivs kan du ta en titt på Person.java i
exemplen. Till denna har jag skapat tre testklasser. Den första, PersonTest1, skapar
ett objekt på vanligt sätt som vi hittills gjort. I PersonTest2 använder vi
Bufferedreader för att fråga användaren efter vilket namn och personnummer
objektet ska ha. I PersonTest3 använder vi dialogrutor för att fråga efter objektets
data.
Robert Jonsson
ITM Östersund
Sida 36