11. előadás
Egyenlőségvizsgálat
Az == objektum azonosságot vizsgál
Time t1 = new Time(13, 30);
Time t2 = new Time(13, 30);
System.out.println(t1 == t2); //Nem így van, hiszen ez a REFERENCIÁKAT hasonlítja össze, nem az értékeket
t2 = t1;
System.out.println(t1 == t2);
Helyette az equals függvényt használjuk (tartalmi egyenlőség vizsgálat):
Time t1 = new Time(13,30);
Time t2 = new Time(13,30);
System.out.println( t1 == t2 ); // false
System.out.println( t1.equals(t2) ); // true
Az equals függvény az Object-ben van definiálva (tehát minden objektumból elérhető)
Felüldefiniálás
Az equals szerződés betartandó:
- Ekvivalencia-reláció
- Ha
a != null, akkor!a.equals(null)- Viszont
null.equals(a)\(\Rightarrow\)NullPointerException
- Viszont
- Konzisztens a
hashCode()metódussal- egyenlő objektumok hashCode-ja egyezzen meg
- különböző objektumok hashCode-ja jó, ha különböző
Alapértelmezetten az Equals csak objektumvizsgálatot csinál
A fordító nem ellenőrzi
Szabályos felüldefiniálás
public class Time {
@Override
public boolean equals( Object that ){
// "Gyorsító feltétel": Ha a két objektum "object equal", akkor TrIvIáLiSaN megegyeznek
if(this == that) return true;
// `that` nem null, és Time-ból származik le
if( that != null
&& getClass().equals(that.getClass()) ){
Time t = (Time)that;
// Mezők megegyeznek
return hour == t.hour && minute == t.minute;
} else {
return false;
}
}
@Override public int hashCode(){ return 60*hour + minute; }
}
Jellemző hiba
Jellemző fordítási hiba az @Override-nak köszönhetően
- Minkénképp
Objectkell, hogy legyen a paramétere - Amikor a
Time-osat használjuk, akkor valójában túlterhelés történik - Elhagyható a
@Override, de rossz gyakorlat- ("Tessék kiírni és nem bonyolítani a kollégák dolgát... Valamint a fordító tud szólni, ha probléma van.")
public class Time{
@Override // Override nem lehetséges, mert a szignatúra csak akkor jó, ha a paraméter Time.
// Elhagyni sem érdemes az Override-ot, mert több problémát okozhat, mint megold
public boolean equals( Time that ){
return that != null && hour == that.hour && ...
}
@Override public int hashCode(){
return 60 * hour + minute;
}
}
Túlterhelés
"This is a bad idea"
~Kozsik
static void connect( Employee e, Manager m ){
m.addUnderling(e);
}
static void connect( Manager m, Employee e ){
m.addUnderling(e);
}
Bármilyen sorrendben megadhatóak az Employee-k és a Manager-ek
A nyelv ezt is elfogadja
DE! Két Manager esetén nem mondható meg, hogy melyik metódust kéne lehívni, fordítási hiba.
Helyette lehetne connect(mike,(Employee)mary);, de az se túl szép.
Tanulság: Soha ne terheljünk túl altípuson!
Öröklődés és equals
public class ExactTime extends Time { ...
// A megörökölt `equals`-t felhasználja
@Override
public boolean equals( Object that ){
return super.equals(that) && second == ((ExactTime)that).second;
}
// A megörökölt `hashCode`-ot felhasználja
@Override
public int hashCode(){
return 60*super.hashCode() + second;
}
}
instanceof, getClass ... equals helyett
public class Time {
//...
@Override
public boolean equals( Object that ){
if( this == that ) return true;
if( that instanceof Time ){
Time t = (Time)that;
return hour == t.hour && minute == t.minute;
} else return false;
}
@Override
public int hashCode(){ return 60*hour + minute; }
}
Ez akkor is működik, ha that altípusa Time-nak, DE problémákat okozhat (pl. a másodpercek egyenlőségét nem teszteli).
final metódus
- nem definiálható felül
public class Time {
// ...
@Override
public final boolean equals( Object that ){
if( that instanceof Time ){
Time t = (Time)that;
return hour == t.hour && minute == t.minute;
} else return false;
}
}
ExactTime e1 = new ExactTime(11,22,44);
ExactTime e2 = new ExactTime(11,22,33);
e1.equals(e2) // RST, de nem ,,igazi" egyenlőség
final class
- Nem lehet belőle leszármaztatni
- Nem lehet specializálni, felüldefiniással belepiszkálni, elrontani
- Módosíthatatlan (immutable) esetben nagyon hasznos
java.lang.Class,java.lang.Integerés egyéb csomagoló osztályok,java.math.BigIntegerstb.