Emneoversikt subklasser INF1010 våren 2008 Uke 4, 22. januar Arv og subklasser Stein Gjessing Institutt for informatikk Mange flere eksempler på fellesøvelsene og neste forelesning 1 Generalisering - spesialisering Gjenbruk av klasser Ved sammensetning (komposisjon) Ved arv Referanser - pekere Klasse-hierarkier Virtuelle metoder Nøkkelordet super Konvertering av referanser Klassen Object Metoden equals() Nøkkelordet instanceof Konstruktører 2 Eksempel: Universitetsregister I et mini-system for universitetet i Oslo skal alle studenter registreres med og telefonnummer (åtte siffer), samt hvilket studie de er tatt opp til. Det skal være mulig for studenter å bytte. Systemet skal også inneholde informasjon om de ansatte ved universitetet, nemlig, telefonnummer, lønnstrinn og antall arbeidstimer per uke. Tekniskadministrativt ansatte har en arbeidsuke på 37.5 timer, mens vitenskapelig ansatte har 40-timers arbeidsuke. Klassen class { String ; int ; String ; System.out.println("Navn: " + ); System.out.println("Telefon: " + ); System.out.println("Studie: " + ); boolean { return >= 10000000 && <= 99999999; void byttprogram(string nytt) { = nytt; 3 4
Klassen Ansatt vs Ansatt class Ansatt { String ; int ; int lønnstrinn; int antalltimer; System.out.println("Navn: " + ); System.out.println("Telefon: " + ); System.out.println("Lønnstrinn: " + lønnstrinn); System.out.println("Timer: " + antalltimer); boolean { return >= 10000000 && <= 99999999; void lønnstillegg(int tillegg) { lønnstrinn += tillegg; 5 Felles variable:, Egne variable: : Ansatt: lønnstrinn, antalltimer Felles metoder: Lignende metoder: skrivdata() Egne metoder: : nyttprogram(string nytt) Ansatt: lønnstillegg(int tillegg) 6 Klassen Kan samle det som er felles i en egen, mer generell, klasse: class { String ; int ; boolean { return >= 10000000 && <= 99999999; og Ansatt som subklasser Kan nå gjøre og Ansatt til subklasser av : class extends { String ; void byttprogram(string nytt) { = nytt; class Ansatt extends { int lønnstrinn; int antalltimer; Angir at klassene og Ansatt er subklasser (= utvidelser) av klassen. void lønnstillegg(int tillegg) { lønnstrinn += tillegg; 7 Hva med skrivdata()? - Kommer tilbake til denne Nytt Java nøkkelord: extends 8
class { String ; int ; String ; boolean {... void byttprogram(string nytt) {... Eksempler på objekter av klassene class { String ; int ; boolean {... class extends { String ; void byttprogram(string nytt) {... 9 Bruk av en subklasse Vi kan bruke variable og metoder i en subklasse på samme måte som om vi hadde definert alt i én klasse: Uten bruk av subklasser (før): class { String ; int ; String ; boolean {... void byttprogram(string nytt) {... Navn: stud Type: eller stud = new (); stud.; String prog = stud.; Med bruk av subklasser (nå): class { String ; int ; boolean {... class extends { String ; void byttprogram(string nytt) {... Navn: stud Type: 10 UML-notasjon for subklassehierarki Hva er en subklasse? class { String ; int ; boolean {... class extends { String ; void byttprogram(string nytt) {... class Ansatt extends { int lønnstrinn; void lønnstillegg (int tillegg){ lønnstrinn += tillegg; Ansatt En subklasse er en klasse som bygger på en allerede spesifisert klasse, og som dermed arver dennes egenskaper i tillegg til å utvide med egne egenskaper (metoder/variable). En subklasse er altså en mer spesialisert utgave av klassen den bygger på. Klassen vi bygger på kalles en superklasse. 11 12
Generalisering spesialisering Mengden av alle er lønnstrinn antalltimer Ansatt Mengden av alle Ansatte Sub-klasse ~ Sub-mengde (del-mengde) Mengden av alle er 13 Klasse-hierarkier Det er mulig å definere subklasser av en subklasse: class { String ; int ; boolean {... class extends { String ; void byttprogram(string nytt){... class Master extends { String veileder; Obs: Her er Master en subklasse av både og, og arver egenskaper fra begge disse. Master veileder 14 Generalisering spesialisering Klasser - Subklasser Mengden av alle er Klassehierarki: Master Mengden av alle Masterer Mengden av alle er Lastebil Bil bil Drosje class Bil {... class bil extends Bil {... class Lastebil extends Bil {... class Drosje extends bil {... veileder 15 16
Klassehierarki: Alle lastebiler bil Lastebil Bil Klasser - Subklasser Drosje class Bil { <lys beige egenskaper> class bil extends Bil { <røde egenskaper> class Lastebil extends Bil { < grønne egenskaper> class Drosje extends bil { < gule egenskaper> Alle biler Alle drosjer Alle personbiler 17 Navn: stud Type: Ulike måter å se et objekt på Navn: pers Typen (klassen) til hele dette objektet er Type: Typen (klassen) til et objekt er uforanderlig. Et objekt kan likevel fremtre for oss på ulike måter. Et objekt av klassen class extends {... kan vi se på som et objekt av typen (klassen) : da er egenskapene som er spesielle for ikke synlige (men de er der fortsatt!). : da er både - og egenskapene synlige for oss. Det er referansens type som avgjør hvordan objektet fremtrer. (med untak av virtuelle metoder, som vi snart skal lære hva er) stud; pers; stud = new (); pers = stud; (Det er lov å skrive: pers = new (); 18 Omdefinering av metoder - polymorfi Polymorfi: eksempel Vi har sett at det med subklasser er mulig å utvide en eksisterende klasse med nye metoder. En subklasse kan også definere en metode med samme signatur som en metode i superklassen, men med ulikt innhold. Den nye metoden vil omdefinere (erstatte) metoden som er definert i superklassen. Metoder som kan omdefineres på denne måten kalles virtuelle metoder. I Java er alle metoder virtuelle, så sant de ikke er deklarert med final. Virtuelle metoder = polymorfi 19 class Hund { //... System.out.println("Voff-voff"); class Rasehund extends Hund { //... System.out.println("Vov-vov"); Anta: Hund h = new Hund(); Rasehund r = new Rasehund(); Hund g = new Rasehund(); For objekter av typen Hund er det denne metoden som gjelder. For objekter av typen Rasehund er det denne metoden som gjelder. Hva skrives ut ved hvert av kallene: h.bjeff(); r.bjeff(); g.bjeff(); 20
Polymorfi: eksempel Nøkkelordet super Hund h Rasehund r Hund g Nøkkelordet super brukes til å aksessere variable / metoder i objektets superklasse. Dette kan vi bruke til å la superklassen ha en generell skrivdata, som så kalles i subklassene: System.out.println("Voff-voff"); System.out.println("Voff-voff"); // I klassen : System.out.println("Navn: " + ); System.out.println("Telefon: " + ); System.out.println("Vov-vov"); // I klassen : super.skrivdata(); System.out.println("Studie: " + ); Anta: Hund h = new Hund(); Rasehund r = new Rasehund(); Hund g = r; Hva skrives ut ved hvert av kallene: h.bjeff(); r.bjeff(); g.bjeff(); voff-voff vov-vov vov-vov // Tilsvarende i klassen Ansatt: super.skrivdata(); System.out.println("Lønnstrinn: " + lønnstrinn); System.out.println("Timer: " + antalltimer); 21 22 Hva slags objekt har jeg? Men: Prøv å unngå instanceof Den boolske operatoren instanceof hjelper oss å finne ut hvilken klasse et gitt objekt er basert på, noe som er nyttig i mange tilfeller: class TestFrukt { public static void main(string[] args) { Eple e = new Eple(); skrivut(e); Hva skjer under kjøring? static void skrivut(frukt f) { if (f instanceof Eple) System.out.println("Dette er et eple!"); else if (f instanceof Appelsin) System.out.println("Dette er en appelsin!"); class Frukt {.. class Eple extends Frukt {.. class Appelsin extends Frukt {.. 23 Istedenfor å teste hvilken klasse objektet er av, be objektet gjøre jobben selv: Bedre class TestFrukt2 { public static void main(string[] args) { Fruk2 f = new Eple2(); f.skrivut( ); class Frukt2 { void skrivut( ) { class Eple2 extends Frukt2 { void skrivut( ) { System.out.println("Dette er et eple!"); class Appelsin2 extends Frukt2 { void skrivut( ) { System.out.println("Dette er en appelsin!");.. Blir det skrevet ut noe? 24
Konvertering av referanser (pekere) Konvertering av referanser (forts.) Anta at vi har: class extends { stud = new (); Hva hvis vi istedenfor hadde hatt: pers = new (); stud = () pers; Ved tilordningen pers; pers = stud; har vi en implisitt konvertering fra - til referanse. Dette godkjennes av kompilatoren, men ved kjøring får vi feilmeldingen java.lang.classcastexception (fordi pers ikke peker på et objekt med alle egenskapene) Hvis vi nå ønsker å få tak i de spesielle egenskapene, må vi foreta en eksplisitt konvertering tilbake til igjen: stud2 = () pers; Dette kalles casting (class-cast) på engelsk, typekonvertering på norsk 25 For å unngå denne feilen, kan instanceof brukes: if (pers instanceof ) { stud = () pers; (Har det objektet pers peker på alle - egenskapene?) 26 Konvertering mellom flere nivåer Konvertering til klassen Object Master master = new Master(); Master Konvertering oppover: stud = master; pers = master; pers stud Konvertering nedover: () pers (Master) pers (fordi dette krever kontroll under kjøring) Master master Regel: Alle pekere har lov til å peke bortover og nedover Alle klasser i Java er subklasser av klassen Object. Når vi skriver class { så tolker Java dette som class extends Object { Dermed kan vi alltid konvertere en referanse oppover til klassen Object: pers = new (); Object obj = pers; For å snakke om egenskapene til -objektet må vi konvertere nedover igjen: () obj (men ikke oppover ) 27 28
Konstruktører Konstruktører og arv Bruk av konstruktører når vi opererer med "enkle" klasser er ganske ukomplisert. Når vi skriver Punkt p = new Punkt(3,4); class Punkt { skjer følgende: int x, y; 1. Det settes av plass i intern-minnet til et objekt av klassen Punkt og til referansen p. 2. Variablene x og y blir deklarert. 3. Konstruktør-metoden blir kalt med x0=3 og y0=4. 4. Etter at konstruktøren har satt x=3 og y=4, settes høyresiden i tilordningen Punkt p = new Punkt(3,4) lik adressen (referansen) til det nye objektet. 5. Tilordningen Punkt p = utføres, dvs p settes lik adressen til objektet. : p type: Punkt Punkt(int x0, int y0) { x = x0; y = y0; : x : y 3 4 type: int type: int Punkt(int x0, int y0) : x0 : y0 3 4 type: int type: int x = x0; y = y0; 29 Det blir noe mer komplisert når vi opererer med arv: Anta at vi har definert en subklasse class B extends A { Hvilken konstruktør utføres hvis vi skriver B bpeker = new B(); Konstruktøren i klassen A? Konstruktøren i klassen B? Begge? 30 Konstruktører og arv (forts.) Kall på super-konstruktøren Anta at vi har deklarert tre klasser: class A { class B extends A { class C extends B { Når vi skriver new C() skjer følgende: 1. Konstruktøren til C kalles (som vanlig) 2. Konstruktøren til C starter med å kalle på B sin konstruktør 3. Konstruktøren til B starter med å kalle på A sin konstruktør 4. Så utføres A sin konstruktør 5. Kontrollen kommer tilbake til B sin konstruktør, som utføres 6. Kontrollen kommer tilbake til C sin konstruktør, som utføres Superklassens konstruktør kan kalles fra en subklasse ved å si: super(); - vil kalle på en konstruktør uten parametre super(5, test ); - om vi vil kalle på en konstruktør med to parametre (int og String) Et kall på super må legges helt i begynnelsen av konstruktøren. Kaller man ikke super eksplisitt, vil Java selv legge inn kall på super( ) helt først i konstruktøren når met kompileres. Hvis en klasse ikke har noen konstruktør, legger Java inn en tom konstruktør med kallet super(); 31 32