Gyakorlati alapok III.
Öröklődés (inheritance)
Az Ős, mely sokasodni foszlik: az Object osztály
A Java API-ról már volt szó a Röviden az API-osztálykönyvtárról című fejezetben:
Ez egy előregyártott, szabadon felhasználható, hivatalos dokumentációval támogatott programcsomag. Léte programozási szempontból roppant mértékű segítség. Szerkezete már egészen a kezdetektől fogva gondosan megtervezett, ezért logikus és következetes egységet alkot, ugyanakkor folyamatosan fejlesztett.
A belső és egységesített logikából következik, hogy osztályok szervezésében hierarchia alakítható ki, legfelül, mintegy "főnöki pozícióban" egy olyan osztállyal, amely az osztályok legáltalánosabb tulajdonságait tartalmazza, valamint olyan tulajdonságokat (metódusokat), amelyek minden osztályra jellemzőek (mindez természetesen a Java rendszeralkotóinak előzetes szándékain-szemléletén múlik). A Java API-ban ez az ősosztály az Object:
Forrás - Source: docs.oracle.com
Érdekességképpen nézzük meg az Object osztály kódját, amely a java.lang csomagban (package) kapott helyett:
public class Object {
private static native void registerNatives();
static {
registerNatives();
}
public final native Class<?> getClass();
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout
value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException("nanosecond
timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
timeout++;
}
wait(timeout);
}
public final void wait() throws InterruptedException {
wait(0);
}
protected void finalize() throws Throwable { }
}
Először is sokszor vehetjük benne észre a native módosítószót. Erről már beszéltünk A hozzáférés-módosítók című fejezetben:
-
native (metódus) - felhasználhat más nyelvekben (C vagy C++) implementált kódot. Nem használható osztályok, interfészek, változók esetében.
Most pedig emeljünk ki közülük néhány gyakran használt metódust!
toString()
Az objektum szöveges reprezentációját adja vissza. Ez persze igen sejtelmes körülírás, hiszen milyen szöveges reprezentációja lehet például egy int visszatérésű függvénynek?
Ha az Object osztályt nem túl elegáns módon példányosítjuk (érdekesmód az osztály nem tartalmaz abstract elemeket /Abstract osztály - abstract metódus című fejezet/, noha az osztályhierarchia legtetején áll) és megnézzük a toString() metódus végeredményét...
public class
Main {
public static void main(String[] args) {
Object object = new Object();
System.out.println(object.toString());
}
}
Végeredmény:
java.lang.Object@15db9742
...akkor a metódus alapértelmezésben a következőt adja vissza:
java.lang.Object@15db9742
Jelentése:
-
rész - az ősosztály neve,
-
rész - @ karakter,
-
rész - előjel nélküli, hexadecimális reprezentációja az Object osztályból keletkezett object objektum hasítókódjának (hash code).
A toString() metódust -ha annak van további értelme-, érdemes felülírni az utódosztályokban, amelyet persze a Java rendszerprogramozói a származtatott API-osztályok esetében folyamatosan meg is tesznek.
További érdekesség, hogy System.out.println(objektumnév) meghívásakor valójában mindig a toString() metódus hívódik meg (alább: System.out.println(object)):
public class
Main {
public static void main(String[] args) {
Object object = new Object();
System.out.println(object);
}
}
Végeredmény:
java.lang.Object@15db9742
getClass()
Visszaadja az objektum alaposztályát:
public class
Main {
public static void main(String[] args) {
Object object = new Object();
System.out.println(object.getClass());
}
}
Végeredmény:
class java.lang.Object
equals()
Összehasonlítja az alapobjektumot egy másikkal és true értéket ad vissza, ha a 2 objektum azonos. Amint az már részletesen ismertetésre került a Mikor egyenlő az egyenlő avagy az equals() függvény című fejezetben, 2 objektum összehasonlítása komoly, sokszor matematikai és más, értelmezési kérdéseket is felvet, ezért nehéz ügy, amint komplikált összehasonlítanunk egy kutyát egy autóval.
Persze némi gondolatbravúrral viszonylag hamar találhatunk közös jellemzőket, amely aztán alapja lehet további összehasonlításoknak, ám ne felejtsük el, hogy mindezt a számítógép felé egzakt módon implementálnunk is kell.
A következő fejezetben majd kiváló példákat láthatunk az ősmetódusok utódokban történő felülírására (overriding), amely gond nélkül elvégezhető, sőt, sok esetben egyenesen ajánlott.