Nejnovější publikace v knižní edici správce české národní domény nese název ESP32 prakticky a jejím autorem je Martin Malý. Kniha je průvodcem ve světě výkonných a velmi bohatě vybavených mikrokontrolérů společnosti Espressif. V knize se naučíte, jak využít tento čip pro různé projekty, od základního nastavení a programování ESP32 v Arduino IDE, přes připojení k Wi-Fi a Bluetooth, až po pokročilé techniky, jako je realtime operační systém FreeRTOS, příjem signálu z družic nebo programování v ESP-IDF.
Byl představen nový oficiální 7palcový Raspberry Pi Touch Display 2. Rozlišení 720 × 1280 pixelů. Cena 60 dolarů.
Na čem aktuálně pracují vývojáři webového prohlížeče Ladybird (GitHub)? Byl publikován přehled vývoje za říjen (YouTube).
Byla vydána verze 0.4.0 v Rustu napsaného frameworku Pingora pro vytváření rychlých, spolehlivých a programovatelných síťových systémů. Z novinek lze vypíchnout počáteční podporu Rustls, tj. implementaci TLS v Rustu. Společnost Cloudflare uvolnila framework Pingora letos v únoru pod licencí Apache 2.0.
Byla vydána první pre-release verze desktopového prostředí Xfce (Wikipedie). Vydání ostré verze je plánováno na 15. prosince. Současně byla vyhlášena soutěž o výchozí wallpaper pro Xfce 4.20. Uzávěrka přihlášek je 15. listopadu.
Přímý přenos z konference OpenAlt 2024, jež probíhá tento víkend v prostorách FIT VUT v Brně. Na programu je spousta zajímavých přednášek. Pokud jste v Brně, stavte se. Vstup zdarma.
V Coloradu unikla hesla k volebním počítačům. Více než 2 měsíce byla tabulka se stovkami hesel do BIOSu volně na webových stránkách. Dle úřadu je potřeba ještě druhé heslo, takže se o žádnou bezprostřední bezpečnostní hrozbu pro volby nejedná [Ars Technica].
Apple kupuje Pixelmator Team stojící za grafickými editory Pixelmator, Pixelmator Pro a Photomator.
Apple představil nový MacBook Pro s čipy M4, M4 Pro a M4 Max.
Na GOG.com běží Halloween Sale 2024. Při té příležitosti lze získat zdarma počítačovou hru Return of the Phantom.
Řešení dotazu:
class Zvíře { public void hlas() { System.out.println("Co to?"); } public void hlasDvakrat() { this.hlas(); this.hlas(); } } class Pes extends Zvíře { @Override public void hlas() { System.out.println("Haf!"); } } class Pudl extends Pes { @Override public void hlas() { System.out.println("Hif hif"); } } Zvíře zvíře = new Pudl(); zvíře.hlasDvakrat(); //vypíše 2× "Hif hif"Mohl byste si myslet, že
zvíře.hlasDvakrat()
, která je definovaná ve třídě Zvíře
, bude volat metodu hlas()
ze „své“ třídy, ale tak to není – voláte metodu hlas()
na instanci třídy Pudl
, takže se zavolá metoda, která je v hierarchii tříd nejbližší Pudlovi (postupuje se jen směrem k rodičům) – a to je metoda přímo ve třídě Pudl
. Kdyby ve třídě Pudl
nebyla ta metoda překrytá, postupuje se výš a najde se ve třídě Pes
. Kdybyste tam nevytvořil instanci Pudla
, ale Psa
, začne se od něj a metoda se najde tam, takže by to vypsalo 2× „Haf!“.
No a pokud v té rodičovské metodě chcete mít možnost zavolat i ten svůj původní kód, dáte ho do nějaké privátní metody a tu pak převoláte z té metody, která je překrytelná. Pak si při volání vyberete, kterou metodu použijete, podle toho, zda chcete použít ten váš kód, nebo kód, který mohl někdo v potomcích přetížit.
class Zvíře { public void hlas() { this.hlasImpl(); } private void hlasImpl() { System.out.println("Co to?"); } public void hlasDvakrat() { this.hlas(); this.hlas(); //nebo this.hlasImpl(); this.hlasImpl(); } }
private
versus všechno ostatní) mění chování kódu. Tady je příklad:
public class Blah { private static class Parent { public void write() { writeOne(); writeTwo(); } private void writeOne() { System.out.println("private parent"); } protected void writeTwo() { System.out.println("protected parent"); } } private static class Child extends Parent { private void writeOne() { System.out.println("private child"); } protected void writeTwo() { System.out.println("protected child"); } } public static void main(String[] unused) { new Parent().write(); new Child().write(); } }
$ javac Blah.java $ java Blah private parent protected parent private parent protected child
@Override
, díky které může překladač kontrolovat, že nepřekrýváte metodu omylem, nebo že naopak nevytváříte novou metodu tam, kde jste chtěl metodu jenom překrýt.
V tomto ohledu je Java trochu prase, protože změna klíčového slova přístupu (private versus všechno ostatní) mění chování kódu.Kdyby jenom
private
metody. U package private metod záleží na tom, v jakém package třída je.
@Override
nepomůže.
@Override
.
@Override
). V některých jazycích se explicitně určuje, co je překrytelná (virtuální) metoda, což u Javy nemá moc význam, protože překrytelné jsou všechny metody, které potomek „vidí“.
final
slouží k tomu, aby bylo možné zakázat překrytí metody, která by jinak podle pravidel mohla být překryta. Existuje v Javě opačné klíčové slovo, které by umožnilo překrýt metodu, která by jinak nemohla být překryta?
final
, takže je evidentní, že jsem v předchozím komentáři psal o těch metodách, které final
nemají.
final
, a tím těžko odlišíte čtyři různé stavy.
@Override
, tedy pokud ji důsledně používáte, berete vážně varování kompilátoru, považujete za řešení upozornění na konflikt jmen a nutnost změny názvu, a pokud při změně knihovny vždy znovu zkompilujete aplikaci. Ale pořád je to lepší, než drátem do oka… A běžné chyby, kdy člověk při psaní kódu omylem překryje něco, co nechtěl, nebo naopak vytvoří novou metodu místo překrytí té z potomka, to odhalí spolehlivě.
To chovani je zcela prizorebe, jak by to podle vas melo fungovat, aby to nebylo "prase"?
Ne, to není přirozené. Ve světě pokřiveném Javou možná ano, ale jinak ne. Všude jinde platí přirozená zásada, že klíčové slovo určující přístupová práva a zapouzdření nemůže samo o sobě změnit chování kódu. Změna takového klíčového slova může samozřejmě způsobit, že se kód nepřeloží (když někdo k metodě ztratí přístup), ale neměla by nikdy nenápadně a bez varování změnit chování kódu. V tomto ohledu je tedy Java prase.
Jak by to mělo fungovat? Jako v C++, ideálně. Odstavec zvaný „Guideline #2: Prefer to make virtual functions private.“ velice pěkně ilustruje, o co se jedná a k čemu to může být užitečné. Že jediná možnost, jak vyrobit v Javě (de facto) nevirtuální metodu, je private
metoda, to je zkrátka smutné (chro chro).
Nevirtuální metody v C++ mají při dědičnosti spoustu hezkých aplikací v případech, kdy se chování přetížené metody podstatně liší od původní implementace a kdy je cílem, aby se metoda na všech objektech z dané hierarchie tříd chovala podle toho, co si volající myslí, že daný objekt je, nikoliv podle toho, o kolik generací dědičnosti složitější je ve skutečnosti volaný objekt. Tohle představuje celkem rozsáhlou třídu design patterns, které v Javě buď vůbec neexistují, nebo jsou dosažitelné jedině lámáním přes koleno.
Jakákoliv obdoba operátoru instanceof
vyžaduje alespoň RTTI nebo případně rovnou runtime jako má Java. Není to tedy univerzálně použitelné řešení. instanceof
je taková poloreflexe, která všeho všudy ukazuje na chyby v návrhu a na zatloukání čtvercových kolíků do kruhových děr. A právě proto to není jedno. Když chci nevirtuální metodu, nechci ji smolit pomocí několika krypticky pojmenovaných protected
, které budou povinně virtuální, jenže co naplat, když chci, aby je potomci viděli, a nebudu při každém volání něco větvit na základě instanceof
. Tyhle zlozvyky z Javy mě pokaždé spolehlivě zvednou ze židle až ke stropu.
Ano, bavíme se skutečně o překrývání. Přetěžování se týká parametrů předávaných „zprava“, zatímco překrývání se týká parametru předávaného „zleva“ (this).
instanceof
neobhajuji. Je to jen berlička pro ty, kteří neumí pracovat s polymorfismem.
Jakákoliv obdoba operátoru instanceof vyžaduje alespoň RTTI nebo případně rovnou runtime jako má Java.Ve skutečnosti to vyžaduje triviální odkaz na informace o třídě, což ale vyžaduje i virtualizace metod.
která všeho všudy ukazuje na chyby v návrhuTo jsou ovšem bez konkrétních příkladů a velmi dobrého zdůvodnění jen prázdná slova.
a na zatloukání čtvercových kolíků do kruhových děr.Na zatloukání čtvercových kolíků do kruhových děr nevidím nic špatného, ty díry jsou tam od toho, aby byl na kolíky trochu prostor, ne aby byly dokonale stejné. Teda aspoň pokud se bavíme o zatloukání kolíků do hlíny. Hromada řečí, argumenty žádné.
private
metody rodiče. Překrýt je ale nemůže. V Javě se prostě to, zda metoda je nebo není virtuální, odvozuje pomocí určitých pravidel z ostatních vlastností té metody. Což na jednu stranu zjednodušuje jazyk (programátor nemusí vědět nic o virtuálních metodách a v obvyklých případech to funguje tak, jak by intuitivně očekával), na druhou stranu to opravdu není úplně čisté řešení. A ještě horší je to na straně potomků, protože tam se to, zda metoda jinou metodu překrývá nebo ne, může změnit, aniž byste ve svém kódu udělal jedinou změnu.
Bud metodu predka ve sve metode vyuziva a vola ji pres super, nebo ji vubec nevyuziva a svoji samostatnou implementaci.O tohle nejde, problém je v opačném směru – pokud kód předka volá překrytou metodu. Normálně by přidání nové metody do rozhraní nemělo být závažnou změnou kontraktu a mělo by být zpětně kompatibilní. Jenže se může stát, že se ta nová metoda zrovna „trefí“ do metody, která už je v potomkovi definovaná, a tím pádem ta metoda v potomkovi najednou nechtěně překryje metodu předka – a bude volána v kontextu, v jakém to nebylo zamýšleno.
public class Rodic { public void run() { step1(); step2(); step3(); } protected void step1() { } protected void step2() { } protected void step3() { } }Aplikace
public class Dite { protected void validate() { } }Knihovna verze 2:
public class Rodic { public void run() { validate(); step1(); step2(); step3(); } protected void step1() { } protected void step2() { } protected void step3() { } protected void validate() { } }
Dite
má být Dite
extends Rodic
. Ale jinak je snad jasné, o co jde – aplikace si ve třídě Dite
nadefinuje nějakou metodu (zde validate()
) pro tuto třídu a její potomky, ta metoda nemá nic společného s rodičovskou třídou. Když ale v rodičovské třídě v další verzi knihovny přibyde virtuální metoda validate()
se správnou signaturou, ta metoda Dite.validate()
najednou bude překrývající metodou. Přitom ta metoda může dělat něco úplně jiného, překrytí nebyl záměr, a dokud se ten kód třídy Dite
znovu nezkompiluje, tak se o tom ani nedozvím. Přitom změna v té knihovně byla zdánlivě zpětně kompatibilní a neměla by rozbít žádný stávající kód.
Duck extends Bird
. Kachna je ptákem. Má křídla jako pták, létá jako pták, ale vydává jiné zvuky než ostatní ptáci. Proto je metoda pro pípání překryta metodou pro kvákání.
A teď: Je nějaký důvod, proč by měla kachna pípat? Není. Proto ani není důvod, proč by se měla volat metoda rodiče, pokud je překryta.
metoda rodiče, pokud je překrytaA v tom je právě ten problém. Já napíšu kód, který metodu rodiče nepřekrývá, a aniž bych ho změnil, najednou nějakou metodu rodiče překrývá.
protected
místo praktičtějšího private
. S tím by se to přece nemohlo stát.
final
...
public class Bird { public static void main(String[] args) { Bird bird = new Duck(); System.out.println(bird.sing()); } public String sing() { return "Beep"; } } class Duck extends Bird { @Override public String sing() { return "Quack"; } }
"Rodičovský podobjekt nemůže poslat překrytelnou zprávu sám sobě. Jakoukoliv překrytelnou zprávu totiž musí poslat znovu „nejvnějšnější“ instanci, v jejíchž útrobách se nachází (dceři, vnučce, pravnučce–prostě té, která už není ničím rodičovským podobjektem)."Materiály rituálně spálit a v případě elektronické podoby rozmlátit médium kladivem. Nejsem nějaký javista, ale pokud vím, tak si zprávy posílají (prostřednictvím volání metod) objekty. Pojem podobjekt dává smysl snad jen v datovém smyslu a chápal bych to u nějakého hrubšího jazyka jako je C nebo C++, ale možná se pletu. Vnější a vnitřní instance a tedy i nejvnějšnější instance mi připadají jako prázdné pojmy. Mám instanci (obecněji objekt), na tu se můžu dívat jako na instanci třídy, kterou skutečně je, nebo jako na instanci některé z nadřazených tříd v hierarchii dědičnosti. Volat metody může kdokoli, kdo ví o dané instanci. Volat může takové metody, které jsou definovány pro třídu pod kterou instance momentálně vystupuje. Ten popis mi připadá jako kdyby používal úplně jinou abstrakci než je v OOP běžná, a které je bližší spíše nějakému fyzickému paměťovému modelu. Ano instance podtřídy opravdu typicky musí nějak uložit podobjekt odpovídající nadtřídě. Ale psát, že tomu podobjektu něco posílá je úplně zbytečná personifikace. Pokud chce člověk mluvit v jazyce hardware, provádějí se instrukce a ukládá se na paměťová místa, pokud chce člověk mluvit v jazyce návrhu, „komunikují“ mezi sebou celé objekty pomocí metod, ale tenhle kočkopes je dobrý možná tak pro vývojáře VM.
Tiskni Sdílej: