čtvrtek 21. října 2010

Dědění od třídy Object

Třída Object stojí na vrcholu hierarchie tříd a každá třída od ní je - přímo či nepřímo - odvozena. Tak to alespoň tvrdí Strom aplikační hierarchie, DictClass.extend() nebo MSDN.
Object definuje několik finálních metod (např. handle()) a čtyři překrytelné (equal(), toString(), wait() a xml()). Znamená to tedy, že každý objekt obsahuje tyto metody? Překvapivě… nikoli.

Zkuste si vytvořit novou třídu, zkonstruovat její instanci a zavolat její metodu toString(). Takový kód vůbec nejde zkompilovat! Pokud tuto instanci přiřadíte do proměnné typu Object, přiřazení je sice korektní a Object obsahuje metodu toString(), takže kompilace proběhne v pořádku, nicméně volání metody vyhodí runtime výjimku.
Object o = new MyClass();
o.toString(); //runtime chyba
Metodu toString() můžete ve své třídě sami naimplementovat a kód bude pochopitelně fungovat. Ale pozor - zde vytváříte nové metody, nepřekrýváte ty ze třídy Object. To má dva zřejmé efekty - zaprvé nemá smysl snažit se volat super() (to platí i pro konstruktor(!)) a za druhé můžete vytvořit metodu stejné signatury jako má některá z finálních metod třídy Object.

Chování, které byste asi očekávali od začátku, je nutné vynutit explicitním uvedením extends Object v classDeclaration vaší třídy. Pak můžete na jejích instancích volat všechny metody zděděné z Object, překrytelné metody se objeví v kontextové nabídce (viz obrázek), můžete volat jejich implementaci ve třídě Object pomocí super() a tak dále.


Řešení pomocí extends Object používají zřejmě veškeré systémové třídy (tzn. třídy v uvedené v System Documentation) a také některé třídy definované v X++, například RunBase.

Zajímavé je, že z pohledu Stromu aplikační hierarchie a DictClass tříd vypadají třídy s i bez extends Object zcela stejně. Popsané chování je také zcela v rozporu s MSDN dokumentací, která například říká: "Methods in the Object class can be called for any object.", tedy "Metody ve třídě Object mohou být volány pro libovolný objekt.".

Zajímavých dopadů by se našlo jistě více, mě napadají tyto:
  • Nelze vytvářet generickou funkcionalitu předpokládající, že všechny objekty v Axaptě mají určitou metodu (třeba equal()), protože to prostě není nijak zaručeno
  • Pokud není třída výslovně deklarována jako potomek Object, může implementovat i finální metody a ty budou zavolány (!!!). Takto lze například vracet libovolně zvolené číslo v handle() - a znamená to, že ani na finální metody třídy Object se nelze stoprocentně spolehnout.
Od této chvíle doporučuji v deklaraci třídy vždy výslovně uvádět extends Object.

Žádné komentáře:

Okomentovat