^ Linux - Friheden til at programmere i Java: Version 0.7.20040516 - 2020-12-31 ^|
| [[java:java-klasser-opg|forrige]] | | [[java:java-arv-poly|næste]] |
----
==== Kapitel 6. Nedarvning ====
Kapitlet forudsættes af resten af bogen.
Forudsætter[[java:java-klasser|Kapitel 5]], Definition af klasser.
I dette kapitel vil vi se på, hvordan man kan genbruge programkode ved at tage en eksisterende klasse og udbygge den med flere metoder og variabler (nedarvning).
==== 6.1. At udbygge eksisterende klasser ====
Hvad gør man, hvis man ønsker en klasse, der ligner en eksisterende klasse, men alligevel ikke helt er den samme?
Svaret er: Man kan definere underklasser, der //arver// (genbruger en del af koden) fra en anden klasse og kun definerer den ekstra kode, der skal til for at definere underklassen i forhold til stamklassen (kaldet superklassen).
Arv er et meget vigtigt element i objektorienterede sprog. Med nedarvning kan man have en hel samling af klasser, der ligner hinanden på visse punkter, men som er forskellige på andre punkter.
=== 6.1.1. Eksempel: En falsk terning ===
Hvis man vil snyde i terningspil, findes der et kendt trick: Bruge sine egne terninger, hvor man har boret 1'er-sidens hul ud, kommet bly i hullet og malet det pænt over, så det ikke kan ses. Sådan en terning vil have meget lille sandsynlighed for at få en 1-er og en ret stor sandsynlighed for at få en 6'er.
Herunder har vi lavet en nedarvning fra Terning til en ny klasse, FalskTerning, ved at starte erklæringen med:
public class FalskTerning extends Terning
Vi har automatisk overtaget (arvet) alle metoder og variabler fra Terning-klassen fordi vi skriver "extends Terning". Dvs. at et FalskTerning1-objekt også har en værdi-variabel og en toString()-metode.
Vi ændrer nu klassens opførsel ved at definere en anden udgave af kast()-metoden:
//// En Terning-klasse for falske terninger.// public class FalskTerning1 //extends Terning// { //// tilsidesæt kast med en "bedre" udgave// //public void kast()// { //// udskriv så vi kan se at metoden bliver kaldt// System.out.print("[kast() på FalskTerning1] ");
værdi = (int) (6*Math.random() + 1); //// er det 1 eller 2? Så lav det om til 6!// if ( værdi <= 2 ) værdi = 6;
}
}
I klassediagrammet er underklassen vist med en hul pil fra FalskTerning1 til Terning.
Dette kaldes også en //er-en// -relation; FalskTerning1 //er en// Terning, da den jo har alle de egenskaber en terning har.
Kort sagt:
> En klasse kan arve variabler og metoder fra en anden klasse
> Klassen, der nedarves fra, kaldes superklassen
> Klassen, der arver fra superklassen, kaldes underklassen
> Underklassen kan tilsidesætte (omdefinere) metoder arvet fra superklassen ved at definere dem igen
Andre steder i litteraturen er der brugt talrige betegnelser for superklasse og underklasse. Her er et udpluk:
**Figur 6-1. Java**
{linuxbog:java:Nordfalk715402.png}
//Superklasse// kaldes også: Baseklasse, basisklasse, forældreklasse, stamklasse.
//Underklasse// kaldes også: Afledt klasse, nedarvet klasse, barn, subklasse.
I vores eksempel er superklassen Terning og underklassen FalskTerning1.
I det følgende program kastes med to terninger, en rigtig og en falsk:
public class Snydespil1
{
public static void main(String[] args)
{
Terning t1 = new Terning();
FalskTerning1 //t2 = new FalskTerning1()// ;
System.out.println("t1: "+t1); //// kunne også kalde t1.toString()// System.out.println("t2: "+t2);
for (int i=0; i<5; i++)
{
t1.kast(); //t2.kast();// System.out.println("t1=" + t1 + " t2=" + t2);
if (t1.værdi == //t2.værdi// ) System.out.println("To ens!");
}
}
}
Resultatet bliver:
[kast() på FalskTerning1] t1: 1
t2: 3
[kast() på FalskTerning1] t1=1 t2=5
[kast() på FalskTerning1] t1=1 t2=3
[kast() på FalskTerning1] t1=4 t2=3
[kast() på FalskTerning1] t1=6 t2=6
To ens!
[kast() på FalskTerning1] t1=2 t2=6
Vi kan altså bruge FalskTerning1-objekter på præcis samme måde som Terning-objekter.
=== 6.1.2. At udbygge med flere metoder og variabler ===
Lad os nu se på et eksempel, hvor vi definerer nogle variabler og metoder i nedarvingen.
**Figur 6-2. Java**
{linuxbog:java:Nordfalk715403.png}
public class FalskTerning2 //extends Terning// { //public int snydeværdi;// //public void sætSnydeværdi(int nySnydeværdi)// {
snydeværdi = nySnydeværdi;
} //public void kast()// {
System.out.print("[kast() på FalskTerning2] ");
værdi = (int) (6*Math.random() + 1); //// 1 eller 2? Så lav det om til snydeværdi!// if ( værdi <= 2 ) værdi = snydeværdi;
}
}
FalskTerning2 har fået en ekstra variabel, snydeværdi, og en ekstra metode, sætSnydeværdi(), der sætter snydeværdi til noget andet.
public class Snydespil2
{
public static void main(String[] args)
{
FalskTerning2 t1 = new FalskTerning2();
t1.sætSnydeværdi(4);
for (int i=0; i<5; i++)
{
t1.kast();
System.out.println("t1=" + t1);
}
}
}
Resultatet bliver:
[kast() på FalskTerning2] [kast() på FalskTerning2] t1=4
[kast() på FalskTerning2] t1=4
[kast() på FalskTerning2] t1=6
[kast() på FalskTerning2] t1=6
[kast() på FalskTerning2] t1=4
=== 6.1.3. Nøgleordet super ===
Nogen gange ønsker man i en nedarvet klasse at få adgang til superklassens metoder, selvom de måske er blevet tilsidesat med en ny definition i nedarvingen. F.eks. kunne det være rart, hvis vi kunne genbruge den oprindelige kast()-metode i FalskTerning.
Med //super// refererer man til de metoder, der er kendt for superklassen. Dermed kan vi skrive en smartere udgave af FalskTerning:
public class FalskTerning3 //extends Terning// { //// tilsidesæt kast med en "bedre" udgave// public void kast ()
{ //super.kast()// ; //// kald den oprindelige kast-metode// //// blev det 1 eller 2? Så lav det om til en 6'er!// if ( værdi <= 2 ) værdi = 6;
}
}
super.kast() kalder kast()-metoden i superklassen. Derefter tager vi højde for, at det er en falsk terning.
----
| [[java:java-klasser-opg|forrige]] | [[java:index|hjem]] | [[java:java-arv-poly|næste]] |
| Opgaver | | Polymorfe variabler |