Arv, polymorfi och gränssnitt Innehåll 2203$ ) UHOlVQLQJ Arv Subtyp, ersättbarhet Olika former av arv Polymorfi Abstrakta klasser och gränssnitt..arv Arv kan delas in i två huvudtyper Arv för specifikation dvs arv av protokoll Arv av kod dvs arv av beteende och struktur Arv kan vara av olika typ Generalisering (eng. extension) subklassen är rikare än, eller en utvidgning av, superklassen Specialisering (eng. specialisation) subklassen är mer specialiserad än, eller ett specialfall av, superklassen Arv är transitivt Om A superklass till B och B superklass till C så ärver C attribut och beteende från både B och A previous next previous next 3 Arv Arv är fundamentalt i objektorienterad programmering För att ett språk skall kallas objektorienterat så måste arv ingå som en möjlig väg att återanvända kod och beskrivningar I programspråksammanhang låter vi subklasser ärva både struktur och attribut från superklasser B E dvs både variabler och metoder ärvs A C D Shape1 extent : Point draw() : void Shape position : Point bounds() :Rectangle draw() : void extent() : Point Shape2 extent : Point draw() : void Boolean Byte Javas basklass Object Klassen Object är överst i Javas klassträd Number Integer String Object equals(obj : Object) : boolean tostring() : String getclass() : String Graphics Klassen Object med några subklasser och några viktiga metoder Component Button Label Container previous next 2 Window Panel previous next 4 Björn Eiderbäck 2000 1 Björn Eiderbäck 2000 2
Exempel: Klassen Circle (klassdiagram) forts //vi ändrar några värden klassnamn attribut här alla publika metoder alla publika två instansmetoder en klassmetod Circle + x : double + y : double + r : double + circumference() : double + area() : double + main(string []) : void circle.x = 100; circle.y = 200; circle.r = 20; // vi gör några testutskrifter System.out.println("Cirkelns x-koordinat: " + circle.x + " och dess y-koordinat: " + circle.y); System.out.println("den har en radie också: " + circle.r); System.out.println( "genom anrop av metoden circumference: " + circle.circumference() + " fick vi omkretsen"); System.out.println("och med area:" + circle.area() + " dess area"); previous next 5 previous next 7 Javakod /* Klassdefinition (utan extends innebär subklass till Object) */ public class Circle { public double x, y; attribut public double r; instansmetoder public double circumference(){return 2 * 3.14 * r; public double area(){return 3.14 * r * r; // för att testa skriver vi en static main-metod // som används då man kör från terminal klassmetod public static void main (String args[]) { //Vi deklarerar en temporär variabel Circle circle; // och instansierar circle = new Circle(); och så sparar vi, kompilerar och kör Spara Spara filen med samma namn som klassen med extension.java, dvs här Circle.java Kompilera javac Circle.java Skapar en fil Circle.class Kör java Circle previous next 6 previous next 8 Björn Eiderbäck 2000 3 Björn Eiderbäck 2000 4
Exempel på UML och Java (från Fii): lampa Exempel: lampa2, med start i on-läge Light1 # ison : boolean + turnon() : void + turnoff() : void + ison() : boolean + toggle() : void + main(string []) : void off toggle toggle on off toggle toggle on previous next 9 previous next 11 Light1, Javakod public class Light1 { protected boolean ison; public void turnon() {ison = true; public void turnoff() {ison = false; public boolean ison() {return ison; public void toggle() {ison =!ison(); public static void main (String args[]) { Light1 light; light = new Light1(); System.out.println(light.isOn()); //ska ge false light.toggle(); System.out.println(light.isOn()); // ska ge true Light2, Javakod public class Light2 { // defultvärde för ison kan anges vid deklarationen protected boolean ison = true; // medlemsmetoderna som förut public static void main (String args[]) { Light2 light; light = new Light2(); System.out.println(light2.isOn()); //true light.toggle(); System.out.println(light.isOn()); //false previous next 10 previous next 12 Björn Eiderbäck 2000 5 Björn Eiderbäck 2000 6
Subklass, subtyp och ersättbarhet Abstrakt datatyp Är en inkapsling av data och dom metoder som opererar på dessa data Subtyp En viss typ A är subtyp till en annan typ B omm A åtminstone erbjuder samma beteende som B och att A kan användas överallt där B kan användas utan att någon skillnad kan observeras Subklass En subklass ärver struktur och beteende från sina superklasser En subklass kan berika, inskränka eller förändra det ärvda beteendet från sina superklasser Ersättbarhet Ett objekt av typ A som är subtyp till typen B kan användas som om det vore av typ B eftersom det åtminstone uppvisar B:s beteende Arv för utvidgning Subklassen lägger till ny funktionalitet i förhållande till superklassen men förändrar inte existerande beteende En Egenskapslista kan implementeras genom att utvidga en HashTable (en hashad tabell med nyckel/värde-par) Arv för begränsning Subklassen inskränker superklassens beteende En MängdKlass kan implementeras som en "inskränkt" Vector Arv för kombination Subklassen ärver från mer än en superklass En Amfibiebil kan implementeras genom att kombinera en Bil med en Båt previous next 13 previous next 15 Olika former av arv Arv för specialisering subklassen är ett specialfall av superklassen, dvs subklassen är en subtyp till superklassen En Tandemcykel är en speciell sorts Cykel Arv för specifikation Superklassen specificerar beteende som inte är implementerat i superklassen men måste implementeras i dess subklasser Ett Fordon specificerar en Bil och Cykel Arv för konstruktion Subklassen utnyttjar superklassens beteende men är inte subtyp till superklassen En FigurGrupp kan implementeras mha av en Vector Exempel: olika typer av arv Arv för specialisering Ellipse Circle Arv för specifikation Win95Window tank engine wheels() speed() Window MotorLandVehicle MacWindow Car Bike Lorry MotorCycle previous next 14 previous next 16 Björn Eiderbäck 2000 7 Björn Eiderbäck 2000 8
Arv för konstruktion Arv för utvidgning Arv för begränsning Polyline Vector Circle Vector Cartoon Stack Ellipse Set Arv för kombination Collection GraphicObject Car Boat GraphicComponent AmfibieCar Fördelar med arv Återanvändning av mjukvara Enkelt att modifiera passande klass (på ett strukturerat sätt) Ökad tillförlitlighet Klasser i "bibliotek" som används av många blir hela tiden testade Delande av kod Likartade komponenter kan dela (stora delar) kod som kan beskrivas i gemensam superklass Överenstämmande gränssnitt Klasser som ärver från gemensam superklass överenstämmer troligare än om dom ärver från separata grenar previous next 17 previous next 19 Modifierare och arv I Java kan vi använda modifierare för att kontrollera arv eller "synbarhet" public kan användas överallt protected kan användas i klass eller subklasser private kan bara användas inne i klassens beskrivning static klassmetod eller klassvariabel final kan ej ändras (variabelfallet), kan ej subklassas (klassfallet) abstract måste specificeras i subklasser ingen package visibility Mjukvarukomponenter Arv gör det enkelt att konstruera återanvändbara komponenter Snabb konstruktion av prototyper Ofta snabbt att återanvända klasser och endast ändra det som skiljer Polymorfi och frameworks Genom polymorfi och arv är det relativt enkelt att beskriva systemstruktur och beteende på hög nivå vars detaljer sedan kan beskrivas av användarnas konkreta subklasser Inkapsling av information Ofta tillräckligt att känna till superklassens protokoll utan detaljer om dess implementation previous next 18 previous next 20 Björn Eiderbäck 2000 9 Björn Eiderbäck 2000 10
Kostnader för arv Exekveringshastighet Viss extra kostnad för metoduppslagning Programstorlek Programbibliotek ger ofta mer binärkod än specialdesignade klasser Programkomplexitet Kod skriven med djupa arvshierarkier ger ofta komplexa strukturer med svårgripbara programflöden Jo-Jo-problemet: där metoder än i superklasser än i subklasser används om vartannat och så prövar vi bla tostring public static void main (String args[]) { Person p1 = new Person("Kalle"); System.out.println(p1); Utmatning i stil med: Namn: Kalle född: Mon Sep 21 15:45:01 MET 1998 previous next 21 previous next 23 Javaexempel: Klass Person med definition av printrutin import java.util.date; public class Person { public String name = ""; public Date dateofbirth; public Person(String name, Date date) {this.name = name; dateofbirth = date; public Person(String name) {this(name, new Date()); public int age(){ Date now = new Date(); return now.getyear() - dateofbirth.getyear(); // med tostring definierar vi hur objektet presenterar sig public String tostring(){ return "Namn: " + name + " född: " + dateofbirth; Vi kan använda super( ) pss som this( ) Ibland vill vi anropa konstruktor i superklassen Då skriver vi super( ), med aktuellt antal argument, så anropas motsvarande konstruktör i superklassen. super( ) måste precis som this( ) stå först Typ() Typ(T t) Typ Undertyp UnderTyp() UnderTyp(T t) super(t); Observera: Om vi varken skriver this( ) eller super( ) så lägger Java implicit in super() först i konstruktorn previous next 22 previous next 24 Björn Eiderbäck 2000 11 Björn Eiderbäck 2000 12
super. super(..) Med super kan vi använda metoder i superklass public class Employee extends Person { // en statisk (klassvariabel) används för att räkna // anställda (dvs egentligen antal instanser) static int numberofemployers = 0; public int number; // Med super kommer vi åt superklassens definition public String tostring(){return super.tostring() + " anställningsnummer: " + number; // för att använda superklassens konstruktor används också //super som skall stå först, med syntax: super(argument) public Employee(String name) { super(name); numberofemployers = numberofemployers + 1; number = numberofemployers; previous next 25 Komposition eller arv Klassen Vector ser förenklat ut på följande sätt: class Vector{ public boolean isempty() { public int size() { public void addelement(object value) { public Object lastelement() { public Object removeelementat(int index) { Nu kan vi konstruera en stack genom att utnyttja Vector med 1) komposition eller 2) arv previous next 27 Mekanismer för återanvändning av mjukvara Ersättbarhet Vi strävar efter att skriva programvara där vissa komponenter kan ersättas av andra utan att påverka några andra delar av systemet Är-en eller har-en Ofta användbar tumregel: använd arv då en komponent är-en (specialisering) av någon annan en tandemcykel är-en cykel, en bil är-ett fordon, en student är-en person använd komposition då en komponent har-en annan komponent som en av sina delar en bil har-em motor, en människa har-en vän Arv av kod eller arv av beteende Arv av gemensam klass bör väljas då kod och struktur delas Ett gränssnitt bör delas då specifikation av beteende men inte den egentliga koden delas komposition Stack isempty() : boolean push(v : Object) : void peek(): Object pop() : Object Stack() : Stack data Vector previous next 26 previous next 28 Björn Eiderbäck 2000 13 Björn Eiderbäck 2000 14
komposition class Stack{ protected Vector thedata; arv class Stack extends Vector{ public void push(object v) {addelement(v); public Stack() {thedata = new Vector(); public boolean isempty() {return thedata.isempty(); public void push(object v) {thedata.addelement(v); public Object peek() {return thedata.lastelement(); public Object pop(){ Object result = peek(); thedata.removeelement(thedata.size() - 1); return result; public Object peek() {return lastelement(); public Object pop(){ Object result = peek(); removeelement(size() - 1); return result; previous next 29 previous next 31 arv Vector Stack push(v : Object) : void peek(): Object pop() : Object Arv eller komposition? Arv ger implicit (eller explicit) antagande om ersättbarhet Subklasser antas vara subtyper Detta "antagande" gäller inte för komposition Komposition är enklare än arv Komposition anger mer tydligt vilka operationer som kan tillämpas på en viss klass Vid arv är subklassernas mängd av operationer en supermängd av superklassens mängd av operationer Programmeraren måste undersöka superklassen för att ta reda på vilka operationer som är legala för subklassen Arv ger kortare beskrivningar än komposition Arv förhindrar inte manipulation av den nya strukturen via ("illegala") operationer i superklassen previous next 30 previous next 32 Björn Eiderbäck 2000 15 Björn Eiderbäck 2000 16
Komposition döljer implementationsdetaljer mer än vad arv gör Det är enkelt att ersätta en viss struktur med en annan En stack kan använda en vektor, byta till en länkad lista eller använda sig av en databas Vid arv har subklasser tillgång till alla icke privata fält i superklassen medan man vid komposition endast har tillgång till publika fält Arv låter oss använda den nya abstraktionen som argument i en polymorf funktion Polymorfa variabler Polymorf från grekiskans poly = många och morf = form En polymorf variabel är en som kan vara deklarerad att hålla ett värde av viss typ men som i verkligheten håller ett värde av en annan typ Ren polymorfi Då en metod kan appliceras på argument av olika typer Överlagring (eller ad hoc polymorfi) En metod med visst namn kan ta olika typer av argument Överskrivning En metod med ett visst namn kan skrivas om (eller skrivas över) i en subklass Abstrakt metod En abstrakt metod är en metod vars signatur är deklarerad i en superklass men implementationen görs i (konkreta) subklasser previous next 33 previous next 35 Vid arv får vi kortare kod än vid komposition. Därmed blir koden mer överskådlig. Å andra sidan är gränssnittet mer tydligt vid komposition Vid arv måste man fråga sig: Vilka delar av den ärvda koden är tänkt att användas? Vilka delar är nödvändiga eller riskabla att initiera respektive förändra? En implementation med arv har en liten fördel i exekveringstid Ett extra funktionsanrop behövs vid komposition Exempel: polymorfi Metoden println i Java kan ta argument av olika typ Klassen PrintStream implementerar tio olika varianter av metoden, allt från en version utan argument, till versioner som tar olika primitiva typer som argument till sådana som tar vektorer, strängar repsktive Object som argument Klassen String implemementerar bla compareto(object) compareto(string) och indexof(int) indexof(int, int) indexof(string) indexof(string, int) previous next 34 previous next 36 Björn Eiderbäck 2000 17 Björn Eiderbäck 2000 18
Överlagring Överlagring och omvandling Vissa överlagrade metoder gör också omvandlingar mellan olika typer av objekt Typexempel aritmetiska operationer (+, -, *, /) där tex en int omvandlas till en float om en float ingår (int float -> float) Överlagring mellan eller inom klasser Metod med visst namn kan finnas i flera klasser Flera metoder med samma namn kan finnas i en viss klass Parmeteröverlagring Olika metoder med samma namn i en viss klass är tillåtna så länge som parametrarna skiljer i antal eller typ Överskrivning Ersätta Koden i superklassen ersätts med kod i subklassen Detta görs genom att metoder med samma namn och argumenttyper som i superklassen definieras om i subklassem Förändra Koden från superklassen kombineras med kod från subklassen Detta görs genom att metod ersätts men att superklassens metod anropas i Java mha super.metod() alternativt i konstruktörer super(..) previous next 37 previous next 39 Exempel: överlagring I en klass för tex grafiska objekt skulle vi kunna ha move(int x, int y) move(point p) En klass Circle skulle kunna ha konstruktörerna Circle(int x, int y, int r) Circle(Point p, int r) Circle(Circle c) Exempel överskrivning Antag att vi har en klass Figure, en subklass Ellipse med subklass Circle Antag att rotation är implementerat via en metod rotate(int angle) i superklasserna En rotation av en cirkel syns inte på skärmen därför skulle vi kunna effektivisera och skriva metoden rotate i Circle på följande sätt public void rotate(int angle) { I Java definierar metoden tostring() hur ett visst objekt skall presenteras vid utskrift på terminal Denna metod är överskriven av flera av klasserna i Java previous next 38 previous next 40 Björn Eiderbäck 2000 19 Björn Eiderbäck 2000 20
Abstrakta metoder och klasser En klass kan deklareras abstrakt Då kan inga instanser av klassen skapas En klass kan deklarera en eller flera av sina metoder som abstrakta Då blir också klassen automatiskt abstrakt Inga instanser av klassen kan därför skapas En subklass blir också abstrakt till dess att alla abstrakta metoder fått en definition Tex om metoderna m1() och m2() deklarerats abstrakta i klassen A men subklassen B endast implementerar m1() så är B också abstrakt Om en klass C deklareras som subklass till B och implementerar m2() så blir C konkret och kan instansieras Exempel: abstrakt klass public abstract class Shape { public abstract double area(); public abstract double circumference(); class Circle extends Shape { proteected double r; protected static final double PI = 3.14; public Circle() {this(1.0); public Circle(double r) {this.r = r; public double area( {return PI * r * r; public double circumference () {return 2 * PI * r; class Rectangle extends Shape { proteected double w, h; public Rectangle (){this(0.0, 0.0); public Rectangle (double w, double h) {this.w = w; this.h = h; public double area() {return w * h; public double circumference() {return 2 * (w + h); previous next 41 previous next 43 Exempel: abstrakt klass abstract class GraphicObject{ int x, y; void moveto(int newx, int newy) { abstract void draw(); class Circle extends GraphicObject { void draw() { class Rectangle extends GraphicObject { void draw() { Vektorer Deklareras på följande sätt Typ[] vektor; Instansiering (tex) vektor = new Typ[10] Kan skapas från primitiva typer int[] tal = new int[5]; tal[0] = 2000; Sytem.out.println(tal[0]); Kan skapas mer direkt Point[] punkter = {new Point(2, 3), new Point(56,72) previous next 42 previous next 44 Björn Eiderbäck 2000 21 Björn Eiderbäck 2000 22
Så kan vi skapa en vektor av Shapes Exempel: interface Konstanter nås via Interfacenamn.konstant tex Sleeper.One_Second Shape[] shapes = new Shape[3]; shapes[0] = new Circle(2.0); shapes[1] = new Rectangle(1.0, 2.0); shapes[2] = new Rectangle(10.0, 20.0); double totalarea = 0; for(int i = 0; i < shapes.length; i++) total_area += shapes[i].area(); public interface Sleeper { public void wakeup(); public long ONE_SECOND = 1000; public long ONE_MINUTE = 60000; public class GUIClock extends Applet implements Sleeper {... public void wakeup() { repaint(); clock.letmesleepfor(this, ONE_MINUTE); previous next 45 previous next 47 Interface Ett interface är som en abstrakt klass med enbart abstrakta metoder och konstanter public interface InterfaceX { public ReturTyp1 m1(x x); public ReturTyp2 m2(y y); En klass kan deklarera att den implementerar ett eller flera interface Observera att en klass endast är direkt subklass till en klass men att den kan implementera flera interface class MinFigur extends Figur implements Interface1, Interface2 { Ett interface kan utvidga ett eller flera andra interface public interface InterfaceN extends Interface1, Interface2, Interface3 {..med interface med följande definitioner public interface Drawable{ public void setcolor(color c); public void setposition(point p); public void draw(window dw); public DrawableRectangle extends Rectangle implements Drawable{ private Color c; private Point pos; public void setcolor(color c) {this.c = c; public void setposition(point p) {pos = p; public void draw(window dw) {dw.drawrect(pos.x, pos.y, height, width); Rectangle previous next 46 previous next 48 Björn Eiderbäck 2000 23 Björn Eiderbäck 2000 24
så kan vi konstruera en vektor av interface (Givet att vi också konstruerat en DrawableCircle och en DrawableSquare på motsvarande sätt) Drawable[] drawables = new Drawable[3]; drawables[0] = new DrawableCircle(2.0); drawables[1] = new DrawableSquare(20.0); drawables[2] = new DrawableRectangle(10.0, 20.0); for(int i = 0; i < drawables.length; i++){ drawables[i].setposition(i * 10.0, i * 5.0); drawables[i].draw(mywindow); previous next 49 Björn Eiderbäck 2000 25