620 likes | 758 Views
Objekt-orientering og Java. Oppfriskning og videreføring av Java-kunnskaper. Forelesningen. Gjennomgang av grunnleggende begreper Klasser og objekter Kjøretidsmodell Spesielle Java-temaer Informasjonsskjuling Teknikker for strukturering av Java-kode Konvensjoner Refactoring-teknikker.
E N D
Objekt-orientering og Java Oppfriskning og videreføringav Java-kunnskaper
Forelesningen • Gjennomgang av grunnleggende begreper • Klasser og objekter • Kjøretidsmodell • Spesielle Java-temaer • Informasjonsskjuling • Teknikker for strukturering av Java-kode • Konvensjoner • Refactoring-teknikker
Objekter og klasser #f34d:C1 a = 1 o = #f350 • Objekter • identitet: hvert objekt er unikt • har en tilstand i form av felt • innkapsling: tilgangen til tilstanden kan begrenses • Klasser • beskriver generelle trekk ved objekter • mal for å lage nye objekter • metoder for å se på og endre objektene • klasser er også objekter:har egen tilstand og egne metoder (og klasser!) • Objekter har én klassetilhørighet livet gjennom • Klassen definerer hva et objekt ”kan” C1:Class b = 2 o = #f34d
Objekter og identitet • hvert objekt er unikt • tradisjonelt angitt med objektets adresse • identiteten kan kun sammenlignes med andre • testes med ==-operator, e.g. o1 == o2 • støtter ikke adresse-aritmetikk <=, >= og +, - • likt innhold betyr ikke lik identitet • equals-metode, e.g. ”!”.equals(s) • ”!”.equals(”!”) er alltid sant • ”!” == ”!” kan være sant! • vær varsom med egen equals-implementasjon • a.equals(b) => b.equals(a) • a.equals(b) => a.hashCode() == b.hashCode()
Identitet og referanser Object o2 #f34d:C a = 1 o = #f350 • tilordning og parameteroverføring • skjer ALLTID vha. referanser (ulikt C og C++) • static boolean foo(Object o1, Object o2){ return o1 == o2;}String a = ”test”, b = a; • både foo(a, a) og foo(a, b) er da sanne • referanser er begrenset til visse typer • null • referanse til ingenting! • e.g. (a != null ? a.foo() : false) • alle objekt-variabler kan tilordnes/referer null-verdien Object o2
Søppel og søppeltømming • Objekter tar plass • hver type data tar en spesifikk mengde plass • objektets plass er omtrent summen av feltene • objekter er ”i live” så lenge referanser finnes • Søppeltømming • referanser holder objekter ”i live”:Object o1 = new Object(), o2 = o1; • hva skjer når siste referanse forsvinner:o1 = null; /* her? */o2 = null; /* her! */ • søppeltømmeren (GC) kommer og tar den! • Objekter tar plass og tømming tar tid
Ikke-objekt-verdier 1 3.14 true ’c’ • Såkalte ”immediate/direkte values” • tall (byte, int, float, double),brukes til aritmetikk • tegn (char, e.g. ’c’),brukes i tekst og filbehandling • sannhetsverdier (true, false),brukes i tester • direkte verdier • tar liten plass, ikke pekere, overføres direkte • syntax for konstanter, e.g. 1, 3.1415, ’c’, true • maskinnære representasjoner ograske operasjoner
Ikke-objekt-verdier... 1 3.14 true ’c’ • Finnes også i objekt-drakt • Integer:a = new Integer(1) => a.intValue() == 1 • ditto for Double/doubleValue(), Character/charValue(), • Boolean:true == new Boolean(true).booleanValue() • bruk Boolean.TRUE/FALSE når Boolean-objekter trengs • Kan ikke endres, e.g. ikke støtte fornew Integer(1).setIntValue(2) • Objekt-varianten er nyttig når: • trenger referanse til ingen verdi: null • referanse til flere typer verdier: Object eller Number • arrays (int[] vs. Integer[] og liste (List))
Arrays • Deklarasjon • <type>[] <variabel>; • <type> <variabel>[]; • Initialisering • <variabel> = {<elt1>, <elt2>, <elt3>, ... ,}; • Tilordning • <variabel> = new <type>[<n>]; • <variabel> = new <type>[] { <elt1>, <elt2>, <elt3>, ... , }; • Referanse • <variabel>[<n>] • Casting • (<subtype>[])(<variabel av type>) • Integer i = ((Integer[ ])(objectArray))[0]; vs. • Integer i = (Integer)((objectArray)[0]);
java.lang.String ”Hello world” eller ”Hello world” • Strenger er objekter • har identitet, lokal tilstand og metoder • e.g. s1 == s2 => s1.equals(s2), ikke omvendt • triks: ”hei”.equals(s), ikke omvendt pga. null • Men: strenger kan ikke endres • s.charAt(0), men ikke s.setCharAt(0, ’c’) • betyr at like strenger kan slås sammen: ”t” == ”t” • Implisitt kreasjon av nye strenger uten new • ”a” + ”b” gir ”ab” • ”1” + 2 gir ”12” • ”objekt: ” + s gir enten ”objekt: null” eller”objekt: ” + s.toString()
String gir lett mye søppel • java.lang.String er bygget på char[] • Strenger lages automatisk av +-operator • String result = ””;for (int i = 0; i < 10; i++) result = result + Integer.toString(i); • result.equals(”0123456789”) er sant • hver iterasjon lager nytt String-objekt og char[]! • StringBuffer er et godt alternativ: • StringBuffer buf = new StringBuffer(10);for (int i = 0; i < 10; i++) buf.append(i);String result = buf.toString(); • bruker mindre hukommelse og er raskere
Klasser og objekter • Klasser beskriver objekter • felt / attributter • funksjoner / operasjoner / metoder • Hvert objekt er av én klasse • skapes med new <klasse>(<parametre>) • klasse-objektet retureres av o.getClass()o = new <klasse>() =>o instanceof <klasse> &&o.getClass() == <klasse>.class • nyttig ved debugging: • System.out.println(o.getClass() + ”:” + o); • objekter kan ALDRI skifte klasse o må være != null
Klasse og objekt... public class C1 { public int f1; public String f2; } Refererer til felt med dott-notasjon: c1.f1 og c1.f2; Objekt Klasse #1234 : C1 f1 = 10 f2 = ”ti” Identitet ogattributter Klassedefinisjon
Arving • en klasse kan bygge på en annen • nye felt og metoder legges til • metoder kan omdefineres • objektene inneholder alle feltene • C2 arver fra C1:o = new C2() =>o instanceof C2 && o instanceof C1 • Men: o.getClass() == C2.class • variabler og referanser • C1 o1 = new C1(); C2 o2 = new C2(); • o1 = o2 er lov, men ikke o2 = o1 • casting (ikke fiske) • o1 = o2; o2 = (C2)o1; // lovlig sekvens!?! • typisk: if (o instanceof C2) ((C2)o).foo(); #f34d:C2 f1 = 1 f2 = ”hei” f3 = true C1 o1 C2 o2 #f34d:C1 f1 = 1 f2 = ”hei”
Arving... public class C2 extends C1 { public boolean f3; } superklassen klasse Objekt #2468 : C2 f1 = 10 f2 = ”ti” f3 = true } Klassedefinisjon C1-del } C2-del
Arving... #2460 : C1 f1 = 10 f2 = ”ti” C1 o1 = new C1(); C1 o2 = new C2(); C2 o3 = (C2)o2; C1 o1 #2468 : C2 f1 = 10 f2 = ”ti” f3 = true C1 o2 } kun C1-del er synliggjennom o2 C2 o3 lov, siden o2faktisk er C2 C2 o3 = (C2)o1; // ulovlig, gir ClassCastException
Konstruktor-metoder og -kall public class C1 { public int f1; public String f2; } public C1(int i, String s) { f1 = i; f2 = s; } new C1(10, ”ti”); Konstruktor-kall ogobjekt Klassedefinisjon ogkonstruktor #1234 : C1 f1 = 10 f2 = ”ti” Identitet ogattributter Først lages boksen av systemet,så kalles konstruktoren, som initialiserer feltene
... konstruktor-metoder new C1(10, ”ti”); public class C1 { public int f1; public String f2; } public C1(int i, String s) { f1 = i; f2 = s; } public C1(int i) { this(i, ”???”); } public C1(String s) { this(s.length()); } #1234 : C1 f1 = 10 f2 = ”ti” new C1(10); #1234 : C1 f1 = 10 f2 = ”???” new C1(”10”); #1234 : C1 f1 = 2 f2 = ”???” En konstruktor kan kalle en annen,vha. this(<parametre>)-konstruksjonen
Initialiseringskode • Alternativ til konstruktorer • class C1 { List l = new ArrayList(); String lString = null; { l.add(”en”); lString = l.toString(); }} • Brukes typisk for å initialisere mer komplekse datastrukturer • Kjøres automatisk før konstruktor-koden aktiveres initialisering av verdi,kun uttrykk/expressions generell kjørbar kode,kan referere til felt
Konstruktorer og arving public class C2 extends C1 { public boolean f3; } public C2(int i, String s, boolean b) { super(i, s); f3 = b; } new C2(10, ”ti”, true); Konstruktor-kall ogobjekt Klassedefinisjon ogkonstruktor #2468 : C2 f1 = 10 f2 = ”ti” f3 = true } C1-del kall til superklassens konstruktor } C2-del super-konstruktoren må kalles først,for å garantere gyldig tilstand
Metoder • Funksjoner / operasjoner / metoder • kode som utføre ”inni” objektet • <referanse>.<metodenavn>(<parametre>), e.g. o.toString() • tilsynelatende som referanse til felt (funksjon som feltverdi!) • kan referere direkte til objektets tilstand • public String toString() { return ”f1= ” + f1 + ”, f2: ” + f2;} • new C1(”10”).toString() => ”f1=2, f2: ???” • public String toString(String prefix) { return prefix + toString(); }
Metoder forts. #2468 : C2 f1 = 10 f2 = ”ti” f3 = true void foo(int delta) { f1 += delta; f3 = ! f3; } foo(1); void foo(int f1) { this.f1 = f1; f3 = ! f3; } foo(11); #2468 : C2 f1 = 11 f2 = ”ti” f3 = false
Metoder... void foo(int f1) { this.f1 = f1; f3 = ! f3; } foo(11); #2468 : C2 f1 = 10 f2 = ”ti” f3 = true #2468 : C2 f1 = 10 f2 = ”ti” f3 = true this foo f1 = 11 foo : C2 this = #2468 f1 = 11
Metoder... • Klasse Bfoo(A a) { a.foo(1); } • Klasse Aboolean b;bar(int i) { b = (i == 2); }foo(int f) { bar(f+1)} : A b = : B : A b = true : B foo a = : A foo f = 1 bar i = 2 • new B().foo(new A());
Metoder og arving class C1 { int f1 = 0;void foo(int delta) { f1+=delta; } } class C2 extends C1 {void foo(int delta) { f1+=delta; super.foo(delta); } } new C2().foo(2); #2468 : C2 f1 = 0 foo = (int) foo = (int) super this foo delta f1 = ?
Metoder og arving... #2468 : C2 foo = (int) bar = (int) foo = (int) bar = (int) class C1 { void foo(int i) { bar(i); } void bar(int i) { ... } } class C2 extends C1 {void foo(int i) { super.foo(i); super.bar(i); } void bar(int i) { ... } } new C2().foo(2); foo : C1 i foo : C2 i vs. Sekvens:C2.foo, C1.foo, C2.bar, C1.bar
Polymorfi • Metodesignatur • typene til parametrene • retur-verdien(?) • eks. public void drawString(String, int, int) • Metodekall • typene til parametrene må stemme med metodesignaturen • f.eks. drawString(”Hello world”, 10, 10+10) • Automatiske konvertering av typer • int til double og float • s + o => s + o.toString(),s + i => s + Integer.toString(i)
Polymorfi... • Samme metodenavn, ulik signatur • teknisk sett ulike metoder • bør ha ”samme” bruk • public int parseInt(String s, int base) { ... } ogpublic int parseInt(String s) { parseInt(s, 10);} • tilsvarende for konstruktorer (<init>) • Bruk når en vil • unngå for mange ulike navnevariasjoner • gjøre API’er hendigere å bruke
Grensesnitt • Metoder = garanti om evner • Algoritmer • formuleres vha. sett av metoder: ”dersom du kan dette, kan jeg gjøre ... med deg” • et objekt har en ”rolle” ift. algoritmen • den egentlige klassen spiller ingen rolle,bare disse metodene er implementert • Klassisk eksempel: sortering • krever mulighet for skanning og sammenligning • to typiske grensesnitt: List og Comparator • List: int size, Object get, void add, void remove, ... • Comparator: int compare, boolean equals • sorteringsalgoritmen trenger kun disse som støtte
Grensesnitt... • Metoder krever: • objekter som kan visse ting • Objekter tilbyr: • sett med metoder • Interface-definisjoner • samler relevante sett med metoder/evner • klasser signaliserer at de implementerer dem • objekter av klasser som implementerer List, kan brukes overalt hvor en List kreves • en klasse kan implementere flere grensesnitt, dvs. inneha flere roller
Grensesnitt i Java • public interface List { public int size(); public boolean contains(Object o); public Object get(int i); public void set(int i, Object o);} • public interface Comparator { // o1 < o2 gir -1, o1 = o2 gir 0, og o1 > o2 gir 1 public int compare(Object o1, Object o2);} • Collection.sort(List, Comparator);
Grensesnitt i Java... • public class IntegerList implements List, Comparator { public int size() { ... } public boolean contains(Object o) { ... } public Object get(int i) { ... } // egentlig Integer public void set(int i, Object o) { ... } // egentlig Integer public int compare(Object o1, Object o2) { int i1 = ((Integer)o).intValue(), i2 = < (Integer)o).intValue(); if (i1 < i2) return -1; else if (i1 > i2) return 1; else return 0; }} • IntegerList il = new IntegerList(); add(il, ...); add (il, ...), ... • Collections.sort(il, il); // sorter liste, med spesifikk sammenligning
Abstrakte klasser • Deklarerer visse evner • Implementerer dem ikke alle selv • Kan ikke lage objekter fra klasse • ”Delvis implementert klasse”,subklasser må implementere resten • Sier eksplisitt hvilke som mangler • Kan arve metoder (forplikte seg), uten å implementere disse
Abstrakte klasser... • public abstract class AbstractList implements List { public boolean contains(Object o) { for (int i =0; i < size(); i++) if (get(i).equals(o)) return true; return false; } // resten av metodene er implisitt abstrakte f.eks. public abstract int size(); // kun deklarasjon, ingen implementasjon ...} • Grensesnitt tilsvarer abstrakt klasse med kun abstrakte metoder (Merk: implements vs. extends)
Grensesnitt-konstanter • Arve av grensesnitt • arv innebærer forpliktelse,ikke gjenbruk av kode • sub-klasse i praksis uavhengig av grensesnitt • Arv av konstanter • grensesnitt kan deklarere konstanter av innebygde type (integer, char, etc.) • konstantene kan nås gjennom sub-klasse • Eks. SwingConstants • LEFT/CENTER/RIGHT, TOP/MIDDLE/BOTTOM
Synlighet av navn • Grensesnitt • gir frihet til reimplementasjon uten endring av ytre forpliktelser • Innkapsling • skjul alt som utsiden ikke trenger å vite • Mekanisme • redusere synlighet av navn • Kunst å la akkurat passe mye være synlig
Synlighet av navn... • ”public” • navn er synlig for alle • felt og metoder ut av klasse • klasse ut av pakke(/klasse) • implisitt i interface-definisjoner • mål å redusere mengden public-navn • reduserer frihet til å endre ting siden • ”private” • navn er ikke synlig • felt og metoder synes ikke utenfor klasse • klasse synes ikke utenfor pakke(/klasse)
Synlighet av navn... • ”protected” • navn er synlig for sub-klasser, via arv • delvis eksponering av detaljer • brukes ofte til hjelpemetoder,f.eks. vanlig i abstrakte klasser • gir mulighet til mer effektive sub-klasser • kan gi utilsiktede bindinger • ”” = pakke-privat • navn inni klasse synlig for alle klasser i samme pakke • brukes blant tett koblede klasser • vanligvis ikke nødvendig
Pakker i Java • Samler sammenhørende klasser • Gjør det lettere å holde oversikt over store API’er • Hierarkisk pakke-struktur • java.lang. - grunnleggende klasser f.eks. Integer, String • java.util. – nyttige hjelpeklasser, f.eks. List • java.awt. – ”gamle” GUI-klasser (inkl. java.awt.event.) • javax.swing. – ”moderne” GUI-klasser (javax angir java-utvidelse) • javax.swing.tree – klasser knyttet til JTree (men ikke JTree selv) • ... • Tilsvarer mappestruktur Meget viktig • filnavn = klassenavn • mappe = pakke • mappehierarki = pakkehierarki
Pakker i Java... • En klasses egentlige navn inneholder pakkenavnet • java.lang.String • java.util.List • javax.swing.JTree; • To måter å referere til en klasse • fullt navn, f.eks. java.lang.List • kombinasjon av import og kortnavn • import java.lang.List; • List l = new java.util.ArrayList(); • import • samles i toppen av fil (før klassedeklarasjonen) • liste med import-setninger gir nyttig oversikt over avhengigheter • importere hele pakker vha. import <pakkenavn>.*;
Jar-filer • Java ARchive • enkeltfil med mappestruktur inni • innpakning av applikasjons pakkestruktur • Kjøring av Java-applikasjon krever • tilgang til mappestruktur med .class-filer (kompilerte java-filer) • jar-fil med tilsvarende katalogstruktur • CLASSPATH (eller –classpath/cp direktiv) • refererer til nødvendige mapper og jar-filer • refererer til mappen som inneholder toppnivå-pakken • må være komplett, slik at alle klasser kan lokaliseres • java –cp vips/classes;jar1.jar;jar2.jar • vanlig at prosjektmappe inneholde src-mappe • kompiler til classes-mappe
Static-modifikator • Klasse som mal for objekter • identitet, feltverdier og initialiseringskode • konstruktorer og metoder håndterer tilstanden • Klassen er også selv et objekt • har navn, ikke identitet • har felt og initialiseringskode • har metoder, men ikke konstruktorer • ”Static” angir felt, kode og metoder av type 2 • Kode kjører i kontekst av klasse, ikke objekt • ”vanlige” klasser er implisitt static
Static-modifikator... • class C { private static List allCs = new ArrayList(); public C() { allCs.add(this); } public static List getAll() { return allCs;}} • new C(); • C.getAll().size() == 1; #:ArrayList C:Class allCs = #:C class
Nøstede klasser • Klasser inni klasser • klasse C1 er konteksten til klasse C2 • to tilfeller, med eller uten static • Static indre-klasse • som vanlig klasse, men spesiell type synlighet • dott-notasjon brukes for benevning • C1.C2 objekt = new C1.C2(); • greit å bruke for å samle kode i en fil
Indre-klasser • Klasse (C2) definert inni annen klasse (C1) • kode i C2 ser navn definert i C1 • C2 arver ikke fra C1, men kan arve fra andre • C2-objekter • inneholder som vanlig egne ogarvede egenskaper • eksisterer alltid i konteksten av C1-objekt • kan referere direkte eller indirekt til C1 sine egenskaper • Bruksområder • et objekt uløselig knyttet til ett annet objekt • behov for å skjule klassen
Indre-klasser... • public class C1 { String n = ””; public C1(String s) { n = s;} public class C2 { public C2() { ... } public getName() { return n;} } public C2 createC2() { return new C2(); }} • new C1(”hal”).createC2().getName() => ”hal” implisitt referanse tilkontekst-objekt #:C1 n = ”hal” C1 #:C2 createC2 getName
Komplisert tilfelle ”ser” C1 fra to kanter • public class C1 { String n = ””; public C1(String s) { n = s;} public class C2 extends C1 { public C2(String s) { super(s); } public getName() { return this.C1.n + n;} } public C2 createC2(String n) { return new C2(n);}} • new C1(”hal”).createC2(”9000”).getName() => ”hal9000” #:C2 n = ”hal” #:C1 n = ”hal” C1 this this createC2 getName kontekstuelt felt vs. arvet
Anonyme indre-klasser • Indre-klasse • har annen klasse som kontekst • arver (extends) eller implementerer (implements) annen klasse • Anonym variant • navnløs klasse defineres i konstruktor-kall • direkte (re)implementasjon av metoder • To typer bruk • direkte implementasjon av grensesnitt • variant av eksisterende (evt. abstrakt) klasse • Svært hendig, men kan virke forkludrende
Anonyme indre-klasser... • List l = new ArrayList(); • ... • Collection.sort(l, new Comparator() { // implementasjon av metode public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2); }}); // vanlig å glemme
Anonyme indre-klasser... • public class MyFrame extends JFrame { public MyFrame() { add(new JPanel() { public void paint(Graphics g) { System.out.println(”paint!”); }}) }}