1 == 1 // true
1 == 2 // false
1 != 2 // true
1.000001 == 1.000001 // true
1.000001 == 1.000002 // false
Math.abs(1.000001 - 1.000002) < 0.001 // true
Obecně rozlišujeme, zda chceme zjišťovat shodnost (rovnost, ekvivalenci):
Rovnost primitivních hodnot zjišťujeme pomocí operátorů:
==
(rovná se)!=
(nerovná se)double
, float
) je třeba porovnávat s určitou tolerancí1 == 1 // true
1 == 2 // false
1 != 2 // true
1.000001 == 1.000001 // true
1.000001 == 1.000002 // false
Math.abs(1.000001 - 1.000002) < 0.001 // true
<
, ⇐
, >=
, >
Uspořádání není definováno na typu boolean , tj. neplatí false < true !
|
1.000001 <= 1.000002 // true
==
vrací true
při rovnosti odkazů, tj. když oba odkazy ukazují na tentýž objekt
equals
vrací true
pri logické ekvivalenci objektů (musí být explicitně nadefinované)
Person pepa1 = new Person("Pepa");
Person pepa2 = new Person("Pepa");
Person pepa3 = pepa1;
pepa1 == pepa2; // false
pepa1 == pepa3; // true
==
==
dostaneme rovnost jen v případě,
jedná-li se o dva odkazy na tentýž objekt.==
vrátí false
.Objekty jsou identické = odkazy obsahují stejnou adresu objektu. |
Rovnost obsahu, metoda equals
:
equals
, kterou je potřeba překrýt.@Override
public boolean equals(Object o)
Object
.<class-name>
, obvykle je potřeba vrátit false
.true
.Dvě komplexní čísla jsou stejná, když mají stejnou reálnou i imaginární část.
public class ComplexNumber {
private int real, imag;
public ComplexNumber(int r, int i) {
real = r; imag = i;
}
@Override
public boolean equals(Object o) {
if (this.getClass() != o.getClass()) return false;
ComplexNumber that = (ComplexNumber) o;
return this.real == that.real
&& this.imag == that.imag;
}
}
Popis kódu na následujícím slajdu:
age
je zbytečné, když máme yearBorn
).String
je objekt, proto pro porovnání musíme použít metodu equals
.instanceof
říká "mohu pretypovat na daný typ".
Metoda equals musí být reflexivní, symetrická i tranzitivní
(javadoc).
|
public class Person {
private String name;
private int yearBorn, age;
public Person(String n, int yB) {
name = n; yearBorn = yB; age = currentYear - yB;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Person)) return false;
Person that = (Person) o;
return this.name.equals(that.name)
&& this.yearBorn == that.yearBorn;
}
}
ComplexNumber cn1 = new ComplexNumber(1, 7);
ComplexNumber cn2 = new ComplexNumber(1, 7);
ComplexNumber cn3 = new ComplexNumber(1, 42);
cn1.equals(cn2); // true
cn1.equals(cn3); // false
Person karel1 = new Person("Karel", 1993);
Person karel2 = new Person("Karel", 1993);
karel1.equals(karel2); // true
karel1.equals(cn1); // false
cn2.equals(karel2); // false
equals
Co když zavolám metodu equals
aniž bych ji přepsal?
Použije se původní metoda equals
ve tříde Object
:
public boolean equals(Object obj) {
return (this == obj);
}
Původní equals
funguje přísným způsobem — rovné jsou jen identické objekty.
Je this.getClass() == o.getClass()
stejné jako o instanceof Person
?
Manager
dědí od Person
, pak:manager.getClass() == person.getClass() // false
manager instanceof Person // true
Co tedy používat?
instanceof
porušuje symetrii x.equals(y) == y.equals(x)
getClass
porušuje tzv. Liskov substitution principlehashCode
equals
nastává dosud nezmíněný problém.equals
, měli bychom současně překrýt i metodu hashCode
.hashCode
je také ve třídě Object
, tudíž ji obsahuje každá třída.@Override
public int hashCode()
Metoda vrací celé číslo pro daný objekt tak, aby:
equals
) objekty musí vždy vrátit stejnou hodnotuint
hashCode
Ipublic class ComplexNumber {
private int real;
private int imag;
...
@Override
public boolean equals(Object o) { ... }
@Override
public int hashCode() {
return 31*real + imag;
}
}
hashCode
IIpublic class Person {
private String name;
private int yearBorn, age;
...
@Override
public boolean equals(Object o) { ... }
@Override
public int hashCode() {
int hash = name.hashCode();
hash += 31*hash + yearBorn;
return hash;
}
}
hashCode
Nejlépe je vytvářet metodu následujícím způsobem (31 je prvočíslo):
@Override
public int hashCode() {
int hash = attribute1;
hash += 31 * hash + attribute2;
hash += 31 * hash + attribute3;
hash += 31 * hash + attribute4;
return hash;
}
A nebo ji generovat (pokud víte, co to dělá :-))
hashCode
HashSet
.equals
(haš mohl být stejný náhodou).contains
lineární!
Jestli se hashCode napíše špatně (nevrací pro stejné objekty stejný haš)
nebo zapomene — množina nad danou třídou přestane fungovat!
|
<, ⇐, >, >=
Comparable
a její metodu compareTo
/