^ 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 |