23.09.2013 Views

Ett kompendium om arv och gränssnitt

Ett kompendium om arv och gränssnitt

Ett kompendium om arv och gränssnitt

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

3 Arv <strong>och</strong> <strong>gränssnitt</strong><br />

3.1 Vad innebär <strong>arv</strong>?<br />

<strong>Ett</strong> objektorienterat språk bygger på att programmeraren ges möjligheten att modellera<br />

verkligheten med hjälp av objekt. Objekt låter sig definieras i form av klasser. Liks<strong>om</strong> i<br />

de flesta objektorienterade språk så tillåter även Java att klasser definieras utifrån andra<br />

klasser. Det är detta s<strong>om</strong> är <strong>arv</strong>.<br />

Arv innebär att man skapar en ny klass (subklass) utifrån en redan existerande klass<br />

(superklass, basklass).<br />

I en objektorienterad terminologi kan vi därför påstå att bilar, motorcyklar, traktorer,<br />

grävskopor <strong>och</strong> bulldozer är olika typer av motorfordon. Motorfordon utgör således en<br />

superklass till de andra fordonen vilka i sin tur är subklasser till motorfordon.<br />

Varje subklass ärver superklassens egenskaper (fält) <strong>och</strong> beteende (metoder). Normalt<br />

lägger man dock till nya egenskaper (nya fält) <strong>och</strong> utökar beteendet (nya metoder).<br />

För att dra en parallell till exemplet ovan så har en grävskopa bl a en metod för att kunna<br />

gräva, detta utgör då ett utökat beteende i förhållande till superklassen motorfordon s<strong>om</strong><br />

inte har detta beteende.<br />

Subklasser kan också <strong>om</strong>definiera superklassens egenskaper <strong>och</strong> beteende, detta är en<br />

viktig mekanism vid <strong>arv</strong>.<br />

För att återgå till exemplet så har alla motorfordon ett inbyggt beteende - att kunna köra<br />

framåt. När du s<strong>om</strong> användare av en motorcykel vill köra framåt vrider du på styrets<br />

gashandtag med handen, vill du åstadk<strong>om</strong>ma samma effekt med en bil trycker du på<br />

gaspedalen med foten. I detta ligger en viktig skillnad. För att kunna använda beteendet<br />

att köra framåt hos olika typer (subklasser) av motorfordon framåt så krävs att detta<br />

beteende implementeras på olika sätt för olika subklasser av motorfordon. Subklasser<br />

tillhandahåller specialiserade beteenden med utgångspunkt i de gemensamma element<br />

s<strong>om</strong> ges av superklassen.<br />

<strong>Ett</strong> bra sätt för att avgöra <strong>om</strong> ett <strong>arv</strong> är lämpligt eller inte är att sätta samman påståendet:<br />

"Subklassen är en/ett superklass ". Om påståendet är jakande så är <strong>arv</strong>et sannolikt<br />

motiverat annars inte. <strong>Ett</strong> undantag skulle givetvis kunna uppträda <strong>om</strong> man idkat dålig<br />

namnsättning på klasserna.<br />

Arv bidrar bl a till<br />

• att skapa en relation (är en/ett) mellan klasserna.<br />

• att kunna återanvända kod (klasser). Detta är speciellt påtagligt i Java då språket<br />

innehåller massor med fördefinierade klasser <strong>och</strong> <strong>gränssnitt</strong>. (Javas API)<br />

• modularisering gen<strong>om</strong> att strukturera program i generell <strong>och</strong> specialiserad kod.<br />

• att det blir lättare att underhålla mjukvaran.<br />

• att det blir lättare att vidareutveckla mjukvaran.


3.2 Syntax vid <strong>arv</strong><br />

I Java kan man endast ärva från en superklass (enkelt <strong>arv</strong>). Dock kan man samtidigt ärva<br />

ett godtyckligt antal s.k. <strong>gränssnitt</strong> (interface).<br />

Arv av en superklass indikeras med nyckelordet extends <strong>och</strong> <strong>arv</strong> av <strong>gränssnitt</strong> indikeras<br />

med nyckelordet implements.<br />

[public] [abstract|final] class <br />

[extends SuperClass] [implements InterfaceList]<br />

{<br />

[Constructors] // initialiseringsmetod(er)<br />

[Fields] // Fält<br />

[Methods] // <strong>och</strong> metoder<br />

}// i godtycklig ordning<br />

Nyckelorden abstract <strong>och</strong> final betyder att klassen inte kan instansieras <strong>och</strong> att den inte<br />

kan ärvas respektive. Mer information <strong>om</strong> abstrakta klasser finns i avsnittet Abstrakta<br />

klasser.<br />

Om man inte anger något <strong>arv</strong> (dvs. extends saknas) så k<strong>om</strong>mer ändå klassen s<strong>om</strong><br />

deklareras att ärva aut<strong>om</strong>atiskt från klassen Object, vilken är en fördefinierad klass i Java<br />

s<strong>om</strong> innehåller en del generella metoder s<strong>om</strong> alla klasser skall ha.<br />

3.3 Generella åtk<strong>om</strong>stregler<br />

Vad gäller kontroll av åtk<strong>om</strong>st så finns public, protected, private <strong>och</strong> default = "åtk<strong>om</strong>st<br />

in<strong>om</strong> paketet” att tillgå. För att använda sig av default-åtk<strong>om</strong>st så utelämnar man<br />

åtk<strong>om</strong>stmodifieraren. Konstruktorer, fält <strong>och</strong> metoder kan använda sig av alla<br />

accessdeklarationer medan klasser endast kan använda sig av public <strong>och</strong> default.<br />

default (”paket åtk<strong>om</strong>st”): Åtk<strong>om</strong>sten s<strong>om</strong> man får <strong>om</strong> man inte anger någon<br />

åtk<strong>om</strong>stmodifierare ger full tillgänglighet in<strong>om</strong> eget paket men ingen åtk<strong>om</strong>st utanför.<br />

public: Klasser, interface <strong>och</strong> medlemmar s<strong>om</strong> är publika är åtk<strong>om</strong>liga överallt förutsatt<br />

att paketet där de deklareras har importeras. Dock är publika medlemmar s<strong>om</strong> ligger i en<br />

klass s<strong>om</strong> endast har default-åtk<strong>om</strong>st normalt inte åtk<strong>om</strong>liga utanför det paketet där de är<br />

deklarerade.<br />

private: Medlemmar s<strong>om</strong> är privata är endast åtk<strong>om</strong>liga in<strong>om</strong> den egna klassen.<br />

protected: Medlemmar s<strong>om</strong> har skyddad åtk<strong>om</strong>st är fullt tillgängliga in<strong>om</strong> eget paket.


3.4 Åtk<strong>om</strong>stregler vid <strong>arv</strong><br />

Klasser måste vara publika för att kunna ärvas av klasser i andra paket. Har klassen<br />

default-åtk<strong>om</strong>st så kan den bara ärvas in<strong>om</strong> eget paket.<br />

I en subklass ärvs alla medlemmar av superklassen med de restriktioner s<strong>om</strong><br />

åtk<strong>om</strong>stmodifierarna i superklassen sätter. Medlemmar s<strong>om</strong> är public nedärvs s<strong>om</strong> public.<br />

Samma sak gäller även för de medlemmar s<strong>om</strong> är protected. Det s<strong>om</strong> är intressant med<br />

medlemmar s<strong>om</strong> har åtk<strong>om</strong>stmodifieraren protected är att dessa nedärvs även av<br />

subklasser s<strong>om</strong> tillhör ett annat paket. M a o medlemmar med skyddad åtk<strong>om</strong>st<br />

(protected) i en publik klass vilken ärvs av klasser i andra paket nedärvs in<strong>om</strong> dessa<br />

subklasser. Vid <strong>arv</strong> så frångås alltså åtk<strong>om</strong>stmodifieraren protected sin generella<br />

restriktion att gälla endast in<strong>om</strong> det egna paketet. Vill man att en medlem av en klass<br />

endast skall kunna ärvas in<strong>om</strong> det egna paketet använder man default-åtk<strong>om</strong>st.<br />

Medlemmar s<strong>om</strong> är private är inte åtk<strong>om</strong>liga ens för subklasser.<br />

<strong>Ett</strong> ord <strong>om</strong> private-medlemmar s<strong>om</strong> inte ärvs. I litteraturen anges ofta att de medlemmar<br />

s<strong>om</strong> är private inte nedärvs. Detta är en sanning med modifikation. En superklass är alltid<br />

en delmängd av en subklass, detta betyder att subklassen faktiskt består av hela<br />

superklassen (inklusive de medlemmar s<strong>om</strong> är private) med eventuellt utökade<br />

egenskaper <strong>och</strong> beteenden. Det enda s<strong>om</strong> åtk<strong>om</strong>stmodifieraren private egentligen<br />

åstadk<strong>om</strong>mer är an accessrestriktion.<br />

3.5 Konstruktorer vid <strong>arv</strong><br />

Konstruktorer ärvs inte.<br />

Om ett objekt instansieras utifrån en subklass så k<strong>om</strong>mer denna att anropa superklassens<br />

konstruktor, <strong>om</strong> superklassen i sin tur är en subklass till en annan klass så k<strong>om</strong>mer denna<br />

att anropa dess konstruktor o s v. Efters<strong>om</strong> en <strong>arv</strong>shierarki kan vara hur djup s<strong>om</strong> helst så<br />

k<strong>om</strong>mer den konstruktor s<strong>om</strong> ingår i den "överst liggande" superklassen att exekvera<br />

först. Konstruktorn för den klass man instansierar ett objekt utav k<strong>om</strong>mer att exekvera<br />

sist.<br />

Om man inte deklarerar någon konstruktor explicit så skapas en defaultkonstruktor s<strong>om</strong><br />

endast anropar en defaultkonstruktor i superklassen. En defaultkonstruktor innehåller<br />

endast satsen:<br />

super();<br />

Om en superklass har en explicit deklarerad konstruktor s<strong>om</strong> skiljer sig från<br />

defaultkonstruktorn, så måste denna också explicit anropas med en super-sats i<br />

subklassens konstruktor. Om superklassen har flera konstruktorer så måste åtminstone en<br />

av dem anropas explicit såvida inte en av dem är defaultkonstruktorn. Denna kan då<br />

anropas aut<strong>om</strong>atiskt av subklassen.


Om en konstruktor initialiserar en variabel så överrider det eventuell initialisering i<br />

variabeldeklarationen.<br />

3.6 Utökning <strong>och</strong> modifiering av beteende<br />

I Java finns det tre viktiga begrepp s<strong>om</strong> har att göra med hur man kan utöka <strong>och</strong><br />

modifiera en klass. Dessa begrepp är<br />

• gömma (hide)<br />

• <strong>om</strong>definiera (redefine) även kallat överrida (override)<br />

• överlagra (overload)<br />

Man kan gömma fält <strong>och</strong> klassmetoder. Att gömma fält innebär att man i subklassen<br />

deklarerar fält med samma namn s<strong>om</strong> finns i superklassen. Då har man gömt<br />

superklassens fält. Att gömma en klassmetod innebär att man i subklassen deklarerar en<br />

klassmetod med samma returtyp, namn <strong>och</strong> parametrar s<strong>om</strong> i superklassen, men med en<br />

annan implementation. Fält <strong>och</strong> klassmetoder kan endast gömmas, de kan inte<br />

<strong>om</strong>definieras eller tas bort.<br />

Man kan <strong>om</strong>definiera instansmetoder. Att <strong>om</strong>definiera en instansmetod innebär att man i<br />

subklassen deklarerar en instansmetod med samma returtyp, namn <strong>och</strong> parametrar s<strong>om</strong> i<br />

superklassen, men med en annan implementering.<br />

Man kan överlagra metoder. Att överlagra metoder (klassmetoder <strong>och</strong> instansmetoder)<br />

innebär att man deklarerar ytterligare metoder med samma namn s<strong>om</strong> en befintlig metod,<br />

men med andra parametrar <strong>och</strong> annan implementering. Överlagring kan göras både av<br />

ärvda metoder (rek<strong>om</strong>menderas ej!) <strong>och</strong> egna metoder.<br />

3.7 Gömmande av fält <strong>och</strong> klassmetoder<br />

Det s<strong>om</strong> kännetecknar gömmande är att det s<strong>om</strong> gömts ”fortfarande finns kvar” i den<br />

meningen att åtk<strong>om</strong>st fortfarande är möjlig enligt deklarerade åtk<strong>om</strong>st regler. För att<br />

k<strong>om</strong>ma åt en instansvariabel s<strong>om</strong> gömts kan man använda en referensvariabel av<br />

superklassens typ eller göra en explicit typecast. Detta gäller även för klassvariabler <strong>och</strong><br />

klassmetoder, dock kan dessa givetvis också accessas direkt utan att något objekt<br />

existerar.<br />

Antag att vi har en gömd instansvariabel ”storlek”, en gömd klassvariabel ”maxStorlek”<br />

<strong>och</strong> en gömd klassmetod ”AndraMaxStorlek()”s<strong>om</strong> ursprungligen deklarerats i klassen<br />

Bild, men s<strong>om</strong> gömts av subklassen Foto. Vi befinner oss i en tredje klass s<strong>om</strong> har<br />

åtk<strong>om</strong>st till klasserna Bild <strong>och</strong> Foto <strong>och</strong> vi har en referensvariabel ”aktuelltFoto” av<br />

klasstypen Foto s<strong>om</strong> refererar till ett objekt av klassen Foto. Då kan vi k<strong>om</strong>ma åt de<br />

gömda sakerna på följande sätt:


Anrop av det nya: Anrop av det gömda:<br />

Bild aktuellBild = (Bild)aktuelltFoto;<br />

int s = aktuelltFoto.storlek; int s = aktuellBild.storlek;<br />

int ms = Foto.maxStorlek int ms = Bild.maxStorlek;<br />

Foto.andraMaxStorlek(); Bild.andraMaxStorlek();<br />

3.7.1 Regler vid gömning<br />

Fält:<br />

• Fält s<strong>om</strong> gömmer behöver inte ha samma typ s<strong>om</strong> det gömda fältet.<br />

• En instansvariabel kan gömma en klassvariabel <strong>och</strong> tvärt<strong>om</strong>.<br />

• Gömmande av fält bör undvikas efters<strong>om</strong> det lätt leder till svårbegripliga program<br />

där man lätt blandar ihop olika variabler med samma namn. Oftast går det inte att<br />

motivera gömmande av fält, detta brukar oftast tyda på att den s<strong>om</strong> gjort det tror<br />

att gömmandet <strong>om</strong>definierar superklassens fält vilket det inte gör.<br />

Metoder:<br />

• En klassmetod kan ej gömma en instansmetod, ej heller kan en instansmetod<br />

gömma en klassmetod efters<strong>om</strong> detta skulle innebära att man försöker<br />

<strong>om</strong>definiera en klassmetod vilket inte är tillåtet.<br />

• Returtyp <strong>och</strong> argument måste vara samma för den metod s<strong>om</strong> gömmer s<strong>om</strong> för<br />

originalet <strong>och</strong> undantag s<strong>om</strong> kastas måste överensstämma.<br />

• Accessen till den gömmande medlemmen måste vara större än eller lika med<br />

accessen till originalet.<br />

3.8 Omdefinition av instansmetoder<br />

Det s<strong>om</strong> kännetecknar <strong>om</strong>definition är att den <strong>om</strong>definierade metoden (gamla metoden)<br />

”inte finns kvar” i den meningen att den är oåtk<strong>om</strong>lig från utsidan av klassen. Den gamla<br />

metoden är dock fortfarande åtk<strong>om</strong>lig in<strong>om</strong> klassen. Detta för att möjliggöra att den<br />

<strong>om</strong>definierande metoden (nya metoden) ska kunna använda den gamla metodens<br />

implementation <strong>om</strong> den vill. Anrop till den gamla metoden sker med hjälp av super:<br />

super.GammalMetod();<br />

Det är viktigt att betydelsen av en metod bibehålls vid <strong>om</strong>definition. I annat fall får man<br />

svårhanterliga program.<br />

3.8.1 Regler vid <strong>om</strong>definition<br />

• Endast instansmetoder kan <strong>om</strong>definieras. En instansmetod kan inte <strong>om</strong>definiera<br />

en klassmetod.


• Omdefinierade metoder måste ha samma signatur (dvs. samma namn <strong>och</strong><br />

parametrar) <strong>och</strong> samma returtyp s<strong>om</strong> originalet i superklassen. Dessut<strong>om</strong> måste<br />

exakt samma undantag deklareras i throws-satsen.<br />

• Utifrån k<strong>om</strong>mer man alltid att anropa de <strong>om</strong>definierade metoderna på ett objekt<br />

oavsett <strong>om</strong> man sätter referenstypen till subklassen eller superklassen.<br />

• Konstruktorn ärvs inte <strong>och</strong> kan således inte <strong>om</strong>definieras.<br />

• Metoder s<strong>om</strong> är final kan inte <strong>om</strong>definieras.<br />

• Metoder s<strong>om</strong> är private kan aldrig <strong>om</strong>definieras.<br />

• Accessrättigheterna för det s<strong>om</strong> <strong>om</strong>definieras/göms måste vara lika eller större än<br />

för det s<strong>om</strong> göms.<br />

3.9 Överlagring av metoder<br />

• Överlagring <strong>och</strong> <strong>om</strong>definiering sker var för sig i Java. Detta är en skillnad mellan<br />

Java <strong>och</strong> C++.<br />

• Överlagrade metoder måste ha samma namn <strong>och</strong> måste ha olika parametrar samt<br />

kan ha olika returtyp. Throws-satserna kan vara olika, dvs. olika undantag kan<br />

kastas.<br />

• Vid ett anrop till överlagrade metoder så bestäms vilken metod man ska ta gen<strong>om</strong><br />

att titta på metodernas signatur (dvs. namn <strong>och</strong> parametrar). Returtypen kan s<strong>om</strong><br />

sagt vara olika mellan de överlagrade metoderna.<br />

• Överlagrade metoder s<strong>om</strong> ärvs kan <strong>om</strong>definieras var <strong>och</strong> en för sig. De metoder<br />

s<strong>om</strong> inte <strong>om</strong>definieras ärvs s<strong>om</strong> de är. Ärvda metoder bör dock överhuvudtaget<br />

inte överlagras efters<strong>om</strong> det leder till svårläst kod.<br />

• Omdefinierade metoder kan överlagras, men detta bör undvikas.<br />

3.10 Objektreferenser i samband med <strong>arv</strong><br />

Fall 1: konvertering av objektreferenser uppåt i <strong>arv</strong>shierarkin.<br />

Om man har en objektreferens till ett objekt av en subklass, så kan denna objektreferens<br />

användas i alla sammanhang där en referens till någon av klassens superklasser kan<br />

användas. Det sker en implicit typkonvertering (cast) i detta fall då man går uppåt i<br />

<strong>arv</strong>shierarkin.<br />

Fall 2: konvertering av objektreferenser nedåt i <strong>arv</strong>shierarkin.<br />

En motsatt situation är <strong>om</strong> man har en referensvariabel s<strong>om</strong> är typad för en superklass,<br />

men s<strong>om</strong> innehåller ett referensvärde till en subklass, <strong>och</strong> man vill tilldela detta<br />

referensvärde till en annan referensvariabel s<strong>om</strong> är typad för subklassen. I detta fall måste<br />

man göra en explicit cast, <strong>och</strong> då bör man först testa med instanceof-operatorn för att<br />

försäkra sig <strong>om</strong> att cast:en är möjlig att göra.


Sådana explicita casts nedåt i <strong>arv</strong>shierarkin enligt fall 2 bör man försöka undvika. Ofta<br />

leder dessa typkonverteringar till att man lyckas generera ett ClassCastException, detta är<br />

också ett fel s<strong>om</strong> uppstår under exekvering, varför risken finns att man kraschar sitt<br />

program. Situationer där man kan frestas till detta går ofta att lösa med polymorfism <strong>om</strong><br />

man från början tänker på det.<br />

3.11 Polymorfism<br />

Polymorfism är en hörnsten i objektorienterad programmering. Det betyder ”många<br />

former”. I Java har alla metoder aut<strong>om</strong>atiskt stöd för polymorfism <strong>och</strong> det krävs inte<br />

något speciellt nyckelord för att beskriva att en metod skall ha möjligheten att vara<br />

polymorf.<br />

Den stora fördelen med polymorfism är att programmeraren inte behöver bry sig <strong>om</strong> att<br />

kontrollera typer, systemet sköter detta. Polymorfism kan realiseras på olika sätt för olika<br />

programmeringsspråk <strong>och</strong> kan därför ges olika innebörder rent praktiskt. I Java har<br />

polymorfism implementerats med s.k. dynamisk bindning, det s<strong>om</strong> är dynamiskt är<br />

typbestämmandet av ett objekt. Typen för ett objekt kan alltså avgöras under exekvering.<br />

Vad är nu detta bra för?<br />

Detta är bra p g a att "rätt" metod kan anropas "aut<strong>om</strong>atiskt". I Java utnyttjas<br />

polymorfism vid <strong>arv</strong> (liks<strong>om</strong> i de flesta objektorienterade språk).<br />

ColourRectangle<br />

void draw();<br />

Color getColor();<br />

Rectangle<br />

void draw();<br />

double area();<br />

ImageRectangle<br />

void draw();<br />

void rotate();<br />

VideoRectangle<br />

void play();<br />

void stop();<br />

I figuren ovan ses en <strong>arv</strong>shierarki där vi har tre subklasser av superklassen Rectangle.<br />

Polymorfism bygger på att vi i subklasserna <strong>om</strong>definierar metoder s<strong>om</strong> ärvs av


superklassen. S<strong>om</strong> ses av figuren ovan så <strong>om</strong>definierar två av subklasserna superklassens<br />

draw() - metod.<br />

Fördelen med detta är att jag kan skapa en referensvariabel till superklassen Rectangle<br />

<strong>och</strong> tilldela denna ett objekt av en subklass.<br />

Rectangle cr = new ColorRectangle(…);<br />

cr.draw();<br />

Trots att cr är deklarerad s<strong>om</strong> en referensvariabel till superklassen Rectangle så<br />

k<strong>om</strong>mer anropet till dess draw() - metod att innebära ett anrop till den draw() - metod<br />

s<strong>om</strong> finns implementerad i klassen ColorRectangle. Detta p g a att<br />

objektet s<strong>om</strong> tilldelats referensvariabeln cr typbestämms vid exekvering.<br />

public void handleRectangle (Rectangle r)<br />

{<br />

…<br />

r.draw();<br />

…<br />

}<br />

Metoden handleRectangle demonstrerar ytterligare nyttan med polymorfism då<br />

denna kan anropas med alla objekt av typen Rectangle eller subklasser härav s<strong>om</strong><br />

argument. Om metoden anropas med en subklass s<strong>om</strong> ej har <strong>om</strong>definierat metoden<br />

draw() så k<strong>om</strong>mer superklassens metod att anropas.<br />

Obs! Endast metoder s<strong>om</strong> deklarerats i superklassen kan anropas på detta sätt:<br />

r.rotate(); går inte!<br />

3.12 Abstrakta klasser <strong>och</strong> metoder<br />

En önskvärd egenskap att ha hos en generell basklass är att kunna definiera metoder s<strong>om</strong><br />

saknar implementation.<br />

Antag att vi har en basklass Figur, vi vet att vi vill ha en metod rita(), men det är<br />

meningslöst att försöka implementera denna då vi inte vet vad för sorts figur s<strong>om</strong> skall<br />

ritas. Om vi däremot gör en subklass Kvadrat till Figur så kan vi ge metoden rita() en<br />

implementation efters<strong>om</strong> vi vet exakt hur en kvadrat skall ritas. Gen<strong>om</strong> att inte ge någon<br />

implementation av metoden rita() i klassen Figur vill vi tvinga alla subklasser att<br />

implementera denna.<br />

De metoder s<strong>om</strong> saknar implementation <strong>och</strong> bara innehåller namn, returtyp <strong>och</strong><br />

parametrar deklareras s<strong>om</strong> abstrakta.


En klass s<strong>om</strong> innehåller en eller flera abstrakta metoder måste deklareras s<strong>om</strong> abstrakt.<br />

Klasser <strong>och</strong> metoder deklareras s<strong>om</strong> abstrakta med hjälp av nyckelordet abstract.<br />

En abstrakt klass kan inte instansieras (efters<strong>om</strong> den helt eller delvis saknar exekverbar<br />

kod), det förutsätts att den ärvs <strong>och</strong> att subklassen implementerar de metoder s<strong>om</strong> är<br />

abstrakta. Att deklarera en abstrakt metod är ett sätt att tvinga en subklass att<br />

tillhandahålla en implementation av metoden. Om subklassen inte tillhandahåller en<br />

implementation av alla abstrakta metoder i superklassen så måste även subklassen<br />

deklareras s<strong>om</strong> abstrakt.<br />

En klass kan deklareras s<strong>om</strong> abstrakt även <strong>om</strong> full implementering finns av alla metoder,<br />

men en sådan klass går trots detta inte att instansiera.<br />

En abstrakt klass kan lämpligen användas när man vill ha en generell basklass, <strong>och</strong> det<br />

inte är möjligt att ge en generell implementation av alla samtliga metoder. (Om samtliga<br />

metoder måste göras abstrakta så är det sannolikt bättre att använda <strong>gränssnitt</strong>.)<br />

3.13 Gränssnitt (Interface)<br />

Gränssnitt kan endast innehålla abstrakta metoder <strong>och</strong> konstanter.<br />

Gränssnitt tillämpas typiskt på så sätt att man definierar ett <strong>gränssnitt</strong> för varje typisk<br />

egenskap s<strong>om</strong> man vill ge en klass, t.ex. Cloneable, Drawable, Storeable, … .<br />

Gränssnittet definierar signatur <strong>och</strong> returtyp för alla metoder s<strong>om</strong> behövs för egenskapen<br />

ifråga, men ingen implementering.<br />

En klass s<strong>om</strong> vill ha en sådan egenskap måste då implementera motsvarande <strong>gränssnitt</strong>.<br />

Java tillåter att ett godtyckligt antal <strong>gränssnitt</strong> implementeras i en klass (multipelt <strong>arv</strong> av<br />

<strong>gränssnitt</strong>), så att man kan ge en klass många olika egenskaper. En klass kan alltså<br />

samtidigt ärva högst en klass men ett godtyckligt antal <strong>gränssnitt</strong>.<br />

En klass s<strong>om</strong> implementerar ett <strong>gränssnitt</strong> måste implementera samtliga metoder i<br />

<strong>gränssnitt</strong>et.<br />

En referensvariabel vars typ är en <strong>gränssnitt</strong>styp kan användas för att referera till alla<br />

objekt s<strong>om</strong> implementerar <strong>gränssnitt</strong>stypen ifråga.<br />

<strong>Ett</strong> <strong>gränssnitt</strong> kan ärva ett eller flera <strong>gränssnitt</strong>, så att man kan bygga upp <strong>gränssnitt</strong><br />

hierarkiskt.


3.14 Gränssnittsdeklaration<br />

[public] interface <br />

[extends SuperInterfaceList]<br />

{<br />

//Konstantdeklarationer<br />

=[,=];<br />

}<br />

//Deklaration av abstrakta metoder<br />

( [Formella parametrar] )<br />

[throws Exceptionklasser];<br />

Nyckelordet extends anger <strong>arv</strong>. <strong>Ett</strong> obegränsat antal superinterface kan ärvas. Klasser kan<br />

inte ärvas av <strong>gränssnitt</strong>.<br />

Alla medlemmar (konstanter <strong>och</strong> metoder) i ett interface har implicit åtk<strong>om</strong>sten public,<br />

<strong>och</strong> är åtk<strong>om</strong>liga i vilket paket s<strong>om</strong> helst förutsatt att interfacet har åtk<strong>om</strong>sten public.<br />

Alla konstanter är implicit public, static <strong>och</strong> final. Dessa modifierare ska alltså inte anges.<br />

Alla metoder är implicit public <strong>och</strong> abstract. Dessa modifierare ska heller inte anges.<br />

3.15 Skillnader mellan <strong>arv</strong> <strong>och</strong> <strong>gränssnitt</strong><br />

• När man ärver en klass ärver man både en specifikation <strong>och</strong> en implementation,<br />

såvida inte klassen är helt abstrakt.<br />

• När man implementerar ett <strong>gränssnitt</strong> så ärver man endast en specifikation.<br />

• Varför kan man inte använda en helt abstrakt klass lika väl s<strong>om</strong> ett <strong>gränssnitt</strong>?<br />

• Arv bör användas då ett verksamhetsmässigt släktskap mellan klasser råder. Om<br />

ett sådant finns så är det osannolikt att en generell basklass inte kan tillhandahålla<br />

någon implementation alls.<br />

• Gränssnitt används för generella, ofta tekniska egenskaper s<strong>om</strong> många orelaterade<br />

klasser ska kunna stödja, ett <strong>gränssnitt</strong> kan jämföras med ett protokoll. <strong>Ett</strong><br />

<strong>gränssnitt</strong> påtvingar inte en klass ett släktskap. Exempel på <strong>gränssnitt</strong> är<br />

Storeable, Drawable, Sendable, Observable etc.<br />

• Om många klasser använder ett visst <strong>gränssnitt</strong> <strong>och</strong> implementationen i klasserna<br />

är någorlunda lika så måste detta <strong>gränssnitt</strong>s implementation upprepas i alla<br />

klasser. Detta är inte i enlighet med objektorienteringens filosofi, att skapa<br />

återanvändbar kod. Lösningen är att koden för att implementera <strong>gränssnitt</strong>et läggs<br />

i en egen klass, <strong>och</strong> alla andra klasser s<strong>om</strong> behöver detta <strong>gränssnitt</strong> skapar ett<br />

objekt av denna klass. När en metod i <strong>gränssnitt</strong>et anropas så vidarebefordras


denna begäran till implementationsobjektet s<strong>om</strong> då hanterar anropet. Denna<br />

teknik kallas delegering.<br />

• Rent praktiskt så är <strong>gränssnitt</strong> också ett sätt att ge en klass fler utökade egenskaper<br />

<strong>och</strong> beteenden än vad s<strong>om</strong> kan ges med ett enkelt <strong>arv</strong>.<br />

• Ytterligare en skillnad s<strong>om</strong> är viktig är att <strong>arv</strong>shierarkin för ett <strong>gränssnitt</strong> <strong>och</strong><br />

<strong>arv</strong>shierarkin för en klass är oberoende. Klasser s<strong>om</strong> implementerar samma<br />

<strong>gränssnitt</strong> kan men behöver inte ha ett släktskap. Detta är en viktig skillnad i<br />

jämförelse med multipelt <strong>arv</strong>, vilket påtvingar ett släktskap.<br />

3.16 Inre klasser<br />

• Det är tillåtet i Java att deklarera klasser (s.k. inre klasser) inuti klasser. De inre<br />

klasserna ligger alltså inbäddade i en annan klass <strong>och</strong> har ingen egen fil. Sådana<br />

inre klasser är bara åtk<strong>om</strong>liga inuti den klass de ligger i. Där kan den inre klassen<br />

instansieras.<br />

• En inre klass kan implementera <strong>gränssnitt</strong> <strong>och</strong> ärva andra klasser på samma sätt<br />

s<strong>om</strong> vanliga klasser.<br />

• Inre klasser ska användas endast till tydligt avgränsade uppgifter s<strong>om</strong> endast berör<br />

den klass de ligger i. Exempel på sådana uppgifter är implementering av<br />

<strong>gränssnitt</strong> eller händelselyssnare.<br />

• En inre klass kan definieras direkt efter new-satsen där den instansieras. Detta<br />

kallas "inline" definition.<br />

• Klasser s<strong>om</strong> behöver användas på många ställen i en applikation ska inte vara inre<br />

klasser.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!