Equals, Hashcode und CompareToMicha Kesslermkessler@next-level-integration.comwww.next-level-integration.com
2
Equals
Hashcode
CompareTo
Inhalt
3
Gibt an, ob zwei Objekte gleich sind
Wir bei Collections benutzt
Nicht sinnvoll zu überschreiben wenn:Logisches equals egal
Jedes Element unterschiedlich
Equals der Superklasse reicht
Wird definitiv nicht benutzt
Equals
4
Reflexivx.equals(x) == true //x != null
Symmetrischx.equals(y) == y.equals(x)
Problematisch bei Ober- und Unterklasse
Transitivx.equals(y) && x.equals(z) y.equals(z)
Problematisch bei Ober- und Unterklasse
Konsistentx.equals(y) jederzeit das gleiche Ergebnis
Problematisch bei veränderlichen Objekten
x.equals(null) == false
Equals
5
public class Point{
private final int x;
private final int y;
public Point(int x, int y){
this.x=x;
this.y=y;
}
@Override
public boolean equals (Object o){
if(!(o instanceof Point)) return false;
Point p = (Point) o;
return p.x == x && p.y == y;
}
}
Equals Beispiel
6
public class ColorPoint extends Point{
private final Color color;
public ColorPoint(int x, int y, Color color){
super(x,y);
this.color = color;
}
@Override
public boolean equals (Object o){
if(!(o instanceof ColorPoint)) return false; return super.equals(o) &&
((ColorPoint) o).color == color;
}
}
Equals Beispiel
7
Symmetrie gebrochen:Point p = new Point(1,4);
ColorPoint cp = new ColorPoint(1,4,Color.RED);
p.equals(cp) != cp.equals(p);
Equals Beispiel
8
@Override
public boolean equals (Object o){
if(!(o instanceof Point))
return false;
if(!(o instanceof ColorPoint))
return o.equals(this);
return super.equals(o) &&
((ColorPoint) o).color == color;
}
Equals Beispiel
9
Transitivität verletzt:Point p = new Point(1,4);
ColorPoint cp1 = new ColorPoint(1,4, Color.RED);
ColorPoint cp2 = new ColorPoint(1,4, Color.BLUE);
cp1.equals(p) -> true
cp2.equals(p) -> true
Aber:cp1.equals(cp2) -> false
Equals Beispiel
10
@Override
public boolean equals (Object o){
if(o == null ||
o.getClass() != getClass())
return false;
Point p = (Point) o;
return p.x == x && p.y == y;
}
Equals Beispiel
11
Liskovsches Substitutionsprinzip:Eigenschaften, die anhand der Spezifikation des vermeintlichen Typs eines Objektes bewiesen werden können, sollten auch dann gelten, wenn das Objekt einem Untertyp dieses Typs angehört.
Gemischter Aufruf false
Equals Beispiel
12
@Override
public boolean equals (Object o){
if(!(o instanceof Point))
return false;
Point p = (Point) o;
return p.canEquals(this) && p.x == x && p.y == y;
}
protected boolean canEquals(Object o){
return o instanceof Point;
}
Equals Beispiel
13
@Override
public boolean equals (Object o){
if(!(o instanceof ColorPoint))
return false;
ColorPoint cp = (ColorPoint) o;
return cp.canEquals(this) && super.equals(cp) && cp.color == color;
}
@Override
protected boolean canEquals(Object o){
return o instanceof ColorPoint;
}
Equals Beispiel
14
Liefert einen Integer-Wert
Gleiche Objekte liefern immer den gleichen Wert
Unterschiedliche Objekte können den gleichen Wert liefern
Hashcode
15
Wenn equals überschrieben wird hashCode überschreiben
Wichtig für HashTable, HashMap und HashSetzwei gleiche Elemente (x.equals(y) == true) können unterschiedliche Hashwerte haben werden nicht gefunden
Alle Elemente, die bei equals eine Rolle spielen, verwendenGute Verteilung
Hashcode
16
Felder umrechnen
boolean: (f ? 1: 0)
byte, char, short, int: (int) f
long: (int) (f^(f>>>32))
float: Float.floatToIntBits(f)
double: Double.doubleToLongBits(f) wie long
Object: rekursiv f.hashcode()
null 0
Hashcode Schema
17
@Override public int hashcode(){int result=5;
result = 31 * result + zahl1;
result = 31 * result + zahl2;
result = 31 * result + feld1.hashcode();
return result;
}
Hashcode Schema
18
private volatile int hashCode;
@Override public int hashcode(){int result = hashCode;
If(result == 0){
result = 5;
result = 31 * result + zahl1;
result = 31 * result + zahl2;
result = 31 * result + feld1.hashcode();
hashCode = result;
}
return hashCode;
}
Hashcode Schema(Cache)
19
public interface Comparable<T>{
int compareTo(T t);
}
Rückgabewert positiv, null oder negativ, wenn das Element kleiner, genau so groß oder größer ist als das this Objekt
ClassCastException wenn der Typ nicht stimmt
NullPointerException wenn null übergeben wird
Schafft eine „Natürliche Ordnung“
Wichtig für interne Aufrufe bei Sortieralgorithmen und Baumstrukturen (z.B. TreeSet, Collections.sort, Array.sort, PriorityQueue, PriorityBlockingQueue, EnumSet)
CompareTo
20
Reflexivx.compareTo(x) == 0
Symmetrischsgn(x.compareTo(y)) == -sgn(y.compareTo(x))
Gilt auch für Exceptions
Transitivsgn(x.compareTo(y)) > 0 && sgn(y.compareTo(z)) > 0 sgn(x.compareTo(z)) > 0
x.compareTo(y) == 0
sgn(y.compareTo(z)) == sgn(x.compareTo(z))
Sollte auch Konsistent zu equals sein(x.compareTo(y) == 0) == (x.equals(y))
CompareTo