jonas.kvarnstrom@liu.se 2015 TDDD78 Viktiga begrepp, del 2
Identitet och likhet Är likhet och identitet samma sak? Oj, vi har samma kläder på oss idag! Nej, men likadana! Besserwisser 3 Detta är två rutor som: Är exakt likadana Men inte samma de har varsin identitet
Två begrepp 4 Motsvarande relaterade men skilda begrepp finns för objekt! Pekar två objektpekare, o1 och o2: På samma objekt? På likadana objekt? Vad betyder detta i Java?
Identitet i Java (vad är "samma" objekt?)
Identitet "Samma objekt" betyder "samma adress" Ser jag två saker i minnet, så är de inte samma sak: Då vore de ju en sak Olika address olika identitet! Datorns minne Object (data) header: x 12.7 y 4.512 r 0.0002 6 Object (data) header: x 12.7 y 4.512 r 0.0002
Identitet och == 7 "Samma objekt" betyder "samma adress" Minne == jämför värdet på två variabler Värdet av en objektvariabel är en pekare (address) name: Nod 1 10000 == jämför pekare name: Nod 2 parent: 10000 49152 == testar om två variabler pekar på samma objekt! nod2.parent == nod3.parent (för 10000 == 10000) name: Nod 3 parent: 10000 Python: is / is not 53284
Identitet och == (exempel) 8 Anta tre variabler som pekar på två objekt: Circle c1 = new Circle(2,2,2); Circle c2 = c1; Circle c3 = new Circle(2,2,2); Då får vi: System.out.println(c1 == c2); // true samma pekare System.out.println(c1 == c3); // false olika objekt (med identiskt innehåll) Object header: (data) c1: c2: Object header: (data) x: 2 c3: x: 2 y: 2 y: 2 r: 2 r: 2
Likhet i Java
Likhet 10 När är likhet intressant i programmering? Vi vill se om två strängar är lika (har samma tecken) Även om de lagras på olika plats i minnet Minne "Hello" "Hello" En mängd kan inte innehålla två lika objekt {12, 13, 12, 13 = {12, 13, antal element = 2 i båda fallen Två cirkelobjekt med samma x/y/radie Vad är likhet?
Likhet: Använd equals() För att jämföra likhet: Använd obj1.equals(obj2) 11 Finns i klassen Object Ärvs ner till alla klasser: Alltid tillgängligt Object Thread Component String AbstractCollection Används av många klasser och metoder List.contains(element) tittar om ett likadant element finns i en lista Ett Set kan inte innehålla element obj1 och obj2 där obj1.equals(obj2)
Likhet: Jämför godtyckliga objekt 12 Måste kunna jämföra objekt utan att veta deras exakta typ! Lösning: equals() tar Object som parameter Accepterar vilken typ av objekt som helst Object.java public class Object { public boolean equals(object other) { MyList.java public class MyList { public boolean contains(object other) { for (int i = 0; i < size(); i++) { if (get(i).equals(other)) return true; return false; equals() finns i alla objekt även get(i) equals() accepterar alla objekt även other
Hur ska equals() fungera?
Likhet: Vid identiskt tillstånd Två objekt med identiskt tillstånd bör oftast vara "lika" Datorns minne 14 a b Object (data) header: x 12.7 y 4.512 r 0.0002 Object (data) header: x 12.7 y 4.512 r 0.0002 Objekten är distinkta (a!= b) Men inga värden skiljer sig åt, bara identiteten Bör anses "lika"! Kan vi definiera likhet på detta sätt?
Likhet: Vid olika tillstånd? Nej: Vissa fält kan vara irrelevanta för likhet Scenario: Vi vill hitta fel i cirkelklassen Lägger till tidsstämpel för när varje objekt skapades Objekten till höger har olika tidsstämpel Vi kan ändå anse att de är "lika"! Datorns minne Object (data) header: x 12.7 y 4.512 r 0.0002 created 4711.31 Object (data) header: x 12.7 y 4.512 r 0.0002 created 4715.77 Vi behöver definiera vad likhet (equality) betyder! 15
Likhet: Fler exempel Vissa fält kan behöva testas "på speciellt sätt" Vi implementerar en mängd Uppsättning element där ordningen inte spelar roll: {a,b,c,d = {d,b,a,c 16 Vi lagrar elementen i en intern lista Listan har en ordning! public class Set { private List elements; public void add(string s) { if (!elements.contains(s)) elements.add(s); Addera element i olika ordning till två mängder m1, m2 m1.elements [a, b, c, d] m2.elements [d, b, a, c] Men m1, m2 är ändå lika! Vi behöver definiera vad likhet (equality) betyder!
Likhet: Standardbeteende 17 Standardbeteendet i Object: Vet inte hur specifika klasser ska jämföras Var konservativ: Riskera inte att returnera sant om objekten är olika Men ett objekt är i alla fall lika med sig själv! Object.java public class Object { public boolean equals(object other) { return this == other; I andra klasser: Overriding! (Redan gjort i Javas egna klasser) Circle.java public class Circle { public boolean equals(object other) {
Implementera equals(): Overriding 18 En cirkel kan ju bara vara lika med en cirkel Vad sägs om detta? Circle.java public class Circle { public boolean equals(circle other) { MyList.java Nej! Detta blir overloading public class MyList { public boolean contains(object other) { for (int i = 0; i < size(); i++) { if (get(i).equals(other)) return true; return false; Vid kompilering av MyList: get(i) returnerar Object Object har en equals: equals(object) Kompilatorn väljer: equals(object) kan inte anropa equals(circle)!
Implementera equals(): Krav Så vi måste ha: Circle.java public class Circle { public boolean equals(object other) { 19 Krav på metoden (kontrakt): Måste vara reflexiv: Måste vara symmetrisk: Måste vara transitiv: Får inte returnera sant för null: x.equals(x) x.equals(y) y.equals(x) x.equals(y) och y.equals(z) x.equals(z) x.equals(null) == false Vi bestämmer oss: Cirklar är lika (equal) om de har samma x, y och radie!
Implementera equals(): Circle En equals() för Circle: Circle.java public class Circle { protected double x, y, r; public boolean equals(object other) { if (other == null) return false; return this.getclass() == other.getclass() && this.x == ((Circle)other).x && this.y == ((Circle)other).y && this.r == ((Circle)other).r; Måste tala om med cast: "Ja, other är egentligen en cirkel" Sedan testar vi det vi menar med likhet: Samma x, y och radie Måste testa om other är av samma klass, Circle 20
Implementera equals(): Objektfält När vissa fält är objekt: Kan vi göra så här? public class ColorCircle { protected double x, y, r; protected Color color; 21 public boolean equals(object other) { if (other == null) return false; return this.getclass() == other.getclass() && this.x == ((Circle)other).x && this.y == ((Circle)other).y && this.r == ((Circle)other).r && this.color == ((Circle)other).color; == testar om other.color pekar på samma färgobjekt Circle gc1 = new GraphicCircle(10, 11, 12, Color.GRAY, new Color(0,0,0)); Circle gc2 = new GraphicCircle(10, 11, 12, Color.GRAY, new Color(0,0,0)); gc1.equals(gc2) är falskt!
Implementera equals(): Objektfält När vissa fält är objekt: Vi vill oftast göra så här! 22 public class ColorCircle { protected double x, y, r; @NotNull protected Color color; public boolean equals(object other) { if (other == null) return false; return this.getclass() == other.getclass() && this.x == ((ColorCircle)other).x && this.y == ((ColorCircle)other).y && this.r == ((ColorCircle)other).r && this.color.equals(((colorcircle)other).color); Givet att color aldrig är null Annars kan testet ge NullPointerException! equals() testar om det är samma färgnyans
Implementera equals(): Objektfält, null När vissa fält kan vara null: public class ColorCircle { protected double x, y, r; @Nullable protected Color color; 23 public boolean equals(object other) { if (other == null) return false; if (this.getclass()!= other.getclass()) return false; ColorCircle that = (ColorCircle) other; Har vi en färg? Kolla att den är lika med det andra objektets. if (this.color!= null &&!this.color.equals(that.color)) return false; if (this.color == null && that.color!= null) return false; return this.x == that.x && this.y == that.y && this.r == that.r; Har vi ingen färg? Kolla att den andra inte heller har det.
Implementera equals(): Ärvning När vi behöver låta superklassen testa sin likhet: public class Circle { protected double x, y, r; public boolean equals(object other) { if (other == null) return false; return this.getclass() == other.getclass() && this.x == ((Circle)other).x && this.y == ((Circle)other).y && this.r == ((Circle)other).r; 24 public class GraphicCircle extends Circle { @NotNull protected Color outline, fill; public boolean equals(object other) { return super.equals(other) && this.color.equals(((graphiccircle)other).outline) && this.fill.equals(((graphiccircle)other).fill); Superklassen testar: null, klass, superklassens fält Vi testar: Våra nya fält
Implementera equals(): Instanceof Vad hade hänt med instanceof? public class Circle { protected double x, y, r; public boolean equals(object other) { if (other == null) return false; return other instanceof Circle && this.x == ((Circle)other).x && this.y == ((Circle)other).y && this.r == ((Circle)other).r; Circle gc1 = new Circle(10, 11, 12); Circle gc2 = new GraphicCircle(10, 11, 12, Color.GRAY, new Color(0,0,0)); gc1.equals(gc2) är sant! problem 25
Två sorters metoder Instansmetoder Anropas för ett specifikt objekt: mycircle.getradius() 27 Statiska metoder (klassmetoder) Anropas för en klass: Circle.getPI() Kan använda "samma objekt": this Anropa andra metoder Använda fält Det närmaste man kan komma till en "global funktion"
Statiska metoder: Exempel 1 När du startar ett Java-program... Du bestämmer vilken klass som ska "startas" (CircleTest) Java skapar inte ett objekt av den typen Laddar in själva klassen Letar efter en speciell statisk metod: public static void main(string[] args) Om den existerar: Anropar den public class CircleTest { public static void main(string[] args) { 28
Statiska metoder: Exempel 2 29 Att anropa metoder i samma klass: public class CircleTest { public static void main(string[] args) { printusage1(); printusage2(); public void printusage1() { System.out.println("Usage: java MyMain [args]"); public static void printusage2() { System.out.println("Usage: java MyMain [args]"); Samma som this.printusage1() Men this = "nuvarande objektet" Finns inte kompileringsfel! Samma som CircleTest.printUsage2() Fungerar bra!
Statiska metoder: Exempel 3 Men statiska metoder kan så klart anropa icke-statiska! 30 public class CircleTest { public static void main(string[] args) { String first = args[0]; System.out.println(first.length()); println() och length() är inte statiska Fungerar bra: Vi försöker inte använda this
Statiska hjälpmetoder En metod som roten ur : Hör inte naturligt till ett specifikt objekt Behöver inte lagra information som finns kvar när den returnerat 31 Kan vara en statisk hjälpmetod Exempel: java.lang.math public class Circle { public final double x, y, r; // center coordinates, radius public boolean contains(double a, double b) { // Is point (a,b) inside this circle? final double dx = x a; final double dy = y b; final double distance = Math.sqrt(dx * dx + dy * dy); if (distance < r) return true; else return false;
Hjälpklasser Bara statiska metoder en hjälpklass (utility class) Används i undantagsfall Flera associerade funktioner som inte hör ihop med ett specifikt objekt Komplex kod eller används av flera klasser (annars kan det placeras i användande klassen!) 32 Att tänka på: Vill inte kunna skapa objekt av denna klass Skapa en privat konstruktor! public final class Math { /** * Don't let anyone instantiate this class. */ private Math() {
Statiska initialiserare Statiska initialiserare körs när en klass laddas Nästan som en konstruktor, men för klassen class Powers { final static int[ ] powers = new int[32]; 33 static { int pow = 1; for (int i = 0; i < 32; i++) { powers[i] = pow; pow <<= 1; // more code! Initialisera statiska fält för senare användning