Konstruktion av klasser med klasser Klasser kan byggas på redan denierade klasser genom att klassobjekt används som dataattribut när en ny klass beskrivs. Exempel: I En klass PairOfDice kan konstrueras med två attribut av typen Die. I En klass CardDeck kan byggas med hjälp av ett arrayobjekt innehållande 52 objekt av typen Card I En klass ListMap kan konstrueras med hjälp av ListNode-objekt I En klass TrafficSystem kan sättas ihop med objekt ur klasser som Lane, Light, Vehicle... Man brukar säga att detta är en består av -relation (16 november 2009 Klasshierarkier 1 )
Klasshierarkier En ny klass kan också byggas som en specialisering av en bentlig klass. Exempel: I Klassen StackException som används i Stack-klassen är skriven som en subklass till Exception I Om vi har en klass Fordon så kan vi bygga nya klasser som t.ex. Spark, Cykel och Bil. En Bil kan i sin tur vara basklass för klasserna Personbil och Lastbil Fordon Spark Cykel Bil Personbil Lastbil (16 november 2009 Klasshierarkier 2 )
I dessa fall säger man att man har en klasshierarki I Klassen Fordon sägs vara en basklass I Klasserna Spark, Cykel och Bil är subklasser eller underklasser till klassen Fordon I En subklass (t ex klassen Bil) kan användas som basklass för andra klasser (t ex Personbil och Lastbil) Man brukar säga att frasen är en... som... kan användas för att identiera att det är lämpligt att använda sig av en klasshierarki. (16 november 2009 Klasshierarkier 3 )
Arv Ett objekt ur en subklass I har alla basklassens attribut och metoder och I kan lägga till egna Man säger att subklassen ärver basklassens egenskaper. Exempel: Klassen Bil kan ha egenskapen vikt. En Personbil kan tillfoga pantal medan en Lastbil kan tillfoga maxlast. En subklass kan också skriva över basklassens metoder. (16 november 2009 Klasshierarkier 4 )
(16 november 2009 Klasshierarkier 5 ) Unied Modeling Language (UML) Klasshierarkier uttrycks ofta i klassdiagram i UML. Fordon print() : void Spark Cykel print() : void Bil vikt : double print() : void Personbil pantal : int print() : void Lastbil maxlast : double print() : void
Fordonshierarkin i kod public class Fordon { public void print() { System.out.print("Fordon"); public class Spark extends Fordon { public class Cykel extends Fordon { public void print() { System.out.print("Cykel"); public class Bil extends Fordon { double vikt; public Bil( double v ) { vikt = v; public void print() { System.out.print("Bil med vikt " + vikt); (16 november 2009 Klasshierarkier 6 )
Användning Koden... public static void pr(string s) { System.out.print(s); public static void main(string [] args) { Fordon f = new Fordon(); Spark s = new Spark(); Cykel c = new Cykel(); Bil b = new Bil(1.2); pr("f: "); f.print(); pr("\n"); pr("s: "); s.print(); pr("\n"); pr("c: "); c.print(); pr("\n"); pr("b: "); b.print(); pr("\n");... ger utskriften f: Fordon s: Fordon c: Cykel b: Bil med vikt 1.2 (16 november 2009 Klasshierarkier 7 )
(16 november 2009 Klasshierarkier 8 ) Flera subklasser public class Personbil extends Bil { int pantal = 5; public Personbil(double v) { super(v); public Personbil(double v, int ant) { super(v); pantal = ant; public void print() { System.out.print("Person"); super.print(); System.out.print(" och platsantal " + pantal);
(16 november 2009 Klasshierarkier 9 ) Fortsättning av main... Personbil pb1 = new Personbil(1.5); Personbil pb2 = new Personbil(0.9,4); pr("pb1: "); pb1.print(); pr("\n"); pr("vikt b : " + b.vikt + "\n"); pr("vikt pb1: " + pb1.vikt + "\n"); f = b; pr("f: "); f.print(); pr("\n"); f = pb1; pr("f: "); f.print(); pr("\n"); pb1 = (Personbil) f; pr("pb1: "); pb1.print(); pr("\n"); ger utskrifterna pb1: PersonBil med vikt 1.5 och platsantal 5 Vikt b: 1.2 Vikt pb1: 1.5 f: Bil med vikt 1.2 f: PersonBil med vikt 0.9 och platsantal 4 pb1: PersonBil med vikt 0.9 och platsantal 4
(16 november 2009 Klasshierarkier 10 ) Exempel på illegala operationer pb1 = f; pb1 = (Personbil) c; pr("vikt: " + f.vikt); pb1 = (Personbil) f; // om f ej refererar Personbil Den sista kan göras säker genom if ( f instanceof Personbil ) pb1 = (Personbil) f; else... Operatorn instanceof bör sällan användas!
Sammanfattning Om klassen S är en subklass till klassen B och om s är deklarerad som en referens till S och b till B så gäller I Ett objekt ur klassen S har alla attribut och metoder som klassen B har I Om S deklarerar ett attribut som nns i B så överskuggas Bs attribut. I En referens får referera objekt ur deklarerad klass och dess subklasser. I För att konstruktionen b.x (eller b.x()) skall vara tillåten måste attributet (eller metoden) x nnas deklarerad i B eller någon basklass till B. I När man anger ett attribut a via punktnotation p.a så är det hur p är deklarerad som avgör vilket attribut som väljs. I När man anropar en metod m via p.m() så är det typen på det element som p verkligen refererar som avgör vilken metod som väljs (så kallad dynamisk eller sen bindning). (16 november 2009 Klasshierarkier 11 )
(16 november 2009 Klasshierarkier 12 ) Metoder som bara nns i vissa klasser Fordon print() : void Spark Cykel print() : void Bil vikt : double print() : void Personbil pantal : int print() : void skatt() : double Lastbil maxlast : double print() : void skatt() : double Bilar beskattas men beräkningen görs på olika sätt för person- och lastbilar.
(16 november 2009 Klasshierarkier 13 ) Användning av skatt-metoden Bil b = new Lastbil(3., 2.);... if (...) { b = new Personbil(1.2, 5);... double s; s = b.skatt(); s = ((Lastbil) b).skatt(); // Illegalt! Skatt inte finns i b // Riskabelt! if ( b instanceof Lastbil ) // Fungerar men klumpigt och s = ((Lastbil) b).skatt(); // oflexibelt else if ( b instanceof Personbil ) s = ((Personbil) b).skatt(); else s = 0;
Bättre Deniera dessutom en skatt-metod i klassen Bil eller, troligen bättre, i klassen Fordon: Fordon print() : void skatt() : double Spark Cykel print() : void Bil vikt : double print() : void Personbil pantal : int print() : void skatt() : double Lastbil maxlast : double print() : void skatt() : double public class Fordon { public void print() { System.out.print("Fordon"); public double skatt() { return 0; (16 november 2009 Klasshierarkier 14 )
Skyddsnivåer I private Endast åtkomligt från klassens egna metoder I public Åtkomligt för alla I protected Åtkomligt från egna subklasser och klasser i samma paket I package Om ingen skyddsnivå anges så ges alla klasser i samma paket åtkomsträttighet (16 november 2009 Klasshierarkier 15 )
Konstruktorer vid arv Konstruktorer ärvs inte När ett objekt ur en subklass skapas så sker följande: 1. Instansvariablerna får sina defaultvärden 2. En konstruktor för superklassen anropas. Man använder super för att specicera vilken av basklassens konstruktor som skall användas. Om super inte används anropas basklassens parameterlösa konstruktor som då måste nnas. 3. Eventuella initieringsuttryck evalueras och tilldelas respektive instansvariabler 4. Satserna i subklassens konstruktor exekveras Använd super i stället för att upprepa kod! (16 november 2009 Klasshierarkier 16 )
(16 november 2009 Klasshierarkier 17 ) Standardprogramvara i Java Hela Java-miljön bygger på arv och klasshierakier! Exempel: 1. Klasserna för undantag: Throwable med underklasserna Error och Exception med underklasserna... 2. Graska komponenter: Component med underklasser Button, Checkbox, Container,... där t ex Container har underklasserna Panel, Window... 3. Avbildningar: Map med bl a underklassen HashMap 4. Samlingsklasserna: Collection med bl a underklassen och List som bl a har underklasserna Vector och LinkedList (Map, Collection och List är egentligen interface och inte klasser)
Klassen Object Klassen Object är basklass till alla klasser. En referens till Object får således referera vilket objekt som helst. Detta kan utnyttjas för att göra generella samlingsklasser (listor, tabeller... ): class ListNode { Object info; ListNode next; ListHead(Object i, ListNode n) { info = l; next = n; public class List { ListNode head; public void insertfirst(object o) { head = new ListNode(o, head)... (16 november 2009 Klasshierarkier 18 )
(16 november 2009 Klasshierarkier 19 ) Klassen Object forts Några metoder i klassen Object: I Object clone() I boolean equals(object o) I String tostring() Ofta anledning att omdeniera dessa!
Exempel på användning av arv: geometriska gurer Skriv ett program som kan hantera bilder bestående av cirklar, rektanglar och andra geometriska former. Programmet ska kunna I representera ett antal olika gurer, I rita upp en bild av de representerade gurerna, I beräkna den sammanlagda ytan av gurerna och I kunna läsa in hur en bild ska vara uppbyggd. (en rad andra operationer är naturligtvis tänkbara: ytta, rotera, skala... ) (16 november 2009 Klasshierarkier 20 )
(16 november 2009 Klasshierarkier 21 ) Forts geometriska gurer 1. Vilka klasser behövs för att representera gurerna? Circle, Rectangle,... 2. Vilka attribut och metoder ska nnas? I konstruktorer I metod för ytberäkning I metod för att rita 3. Hur skall man representera en mängd sådana gurer? I array? I lista? I annan struktur? Vilken typ skall det vara på elementen i strukturen?
(16 november 2009 Klasshierarkier 22 ) Forts geometriska gurer Shape xcoord : int ycoord : int area() : double paint():void Circle radius: int area(): double paint():void Rectangle width : int height : int area() : double paint():void
(16 november 2009 Klasshierarkier 23 ) Forts geometriska gurer Nu kan vi t ex göra en Shape[] fig = new Shape[100]; fig[0] = new Recatangle(...); fig[1] = new Circle(...);... (fast vi skall använda en mer exibel struktur än en array) Det nns ingen meningsfull implementation av area() och paint() i Shape! Deklarera dessa metoder och klassen Shape som abstract.
(16 november 2009 Klasshierarkier 24 ) Forts geometriska gurer import java.awt.*; public abstract class Shape { protected int xcoord, ycoord; public Shape(int x, int y) { xcoord = x; ycoord = y; public abstract double area(); public abstract void paint(graphics g);
(16 november 2009 Klasshierarkier 25 ) Forts geometriska gurer import java.awt.*; public class Circle extends Shape { protected int radius; public Circle(int x, int y, int r){ super(x,y); radius = r; public double area(){ return Math.PI*radius*radius; public void paint(graphics g){ g.setcolor(color.red); g.filloval(xcoord-radius, ycoord-radius, 2*radius, 2*radius);
(16 november 2009 Klasshierarkier 26 ) Forts geometriska gurer import java.awt.*; public class Rectangle extends Shape { protected int width, height; public Rectangle(int x, int y, int w, int h) { super(x,y); width = w; height = h; public double area(){ return width*height; public void paint(graphics g){ g.setcolor(color.blue); g.fillrect(xcoord,ycoord,width,height);
(16 november 2009 Klasshierarkier 27 ) Forts geometriska gurer För att samla ihop ett antal olika gurer skall vi använda en av Javas samlingsklasser: LinkedList som är en subklass (indirekt) till klassen Collection (egentligen ett interface). För denna uppgifts skull räcker det med att kunna I Skapa ett LinkedList-objekt: Collection<Shape> shapes = new LinkedList<Shape>(); I Lägga in gurer i listan. T ex: shapes.add(new Circle(x,y,r)); I Iterera över elementen och komma åt deras metoder. T ex: for (Shape s:shapes) s.paint();
Forts geometriska gurer import javax.swing.*; import java.awt.*; import java.util.*; public class Drawing extends JPanel { private Collection<Shape> shapes; public Drawing(Collection<Shape> s, int w, int h) { shapes = s; setbackground(color.white); setpreferredsize(new Dimension(w,h)); public double area(){ double a = 0; for (Shape s:shapes) a += s.area(); return a; public void paintcomponent(graphics g){ super.paintcomponent(g); for (Shape s:shapes) s.paint(g); (16 november 2009 Klasshierarkier 28 )
(16 november 2009 Klasshierarkier 29 ) Forts geometriska gurer import javax.swing.*; import java.awt.*; import java.util.*; public class DrawTest extends JFrame { public static void main(string[] args){ Collection<Shape> shapes = read(new Scanner(System.in)); Drawing d=new Drawing(shapes,400,400); System.out.println("Total area: " + (int)d.area()); new DrawTest(d); public DrawTest(Drawing d){ getcontentpane().add(d); pack(); settitle("drawtest"); setdefaultcloseoperation(exit_on_close); setvisible(true);
Forts geometriska gurer private static Collection<Shape> read(scanner sc){ Collection<Shape> shapes = new LinkedList<Shape>(); while (sc.hasnext()){ String s=sc.next(); if (s.equals("circle")){ int x, y, r; x = sc.nextint(); y = sc.nextint(); r = sc.nextint(); shapes.add(new Circle(x,y,r)); else { int x, y, w, h; x = sc.nextint(); y = sc.nextint(); w = sc.nextint(); h = sc.nextint(); shapes.add(new Rectangle(x,y,w,h)); return shapes; (16 november 2009 Klasshierarkier 30 )
(16 november 2009 Klasshierarkier 31 ) Forts geometriska gurer Observera hur klasserna bygger på arv från Javas grak-klasser. Detaljerna i graken är överkurs. Om programmet körs med java DrawTest < figure.txt och len figure.txt har innehållet rectangle 20 50 200 30 circle 350 100 30 rectangle 300 200 50 150 circle 100 300 80
Forts geometriska gurer (16 november 2009 Klasshierarkier 32 )