|
||||||||||||||||||||||||||||||||||||||||||||||||
Menu
Distributions (131)
Software (10844)
|
Java (21) - datové typyJava je jazyk se silnou typovou kontrolou. To sice pomáhá eliminovat mnohé
problémy, přesto nás to nezbavuje nutnosti dbát určitých pravidel. Jejich
zvládnutí však poskytuje až netušené možnosti, co lze v Javě dělat.
Jak nenarazitJsou dvě skupiny programátorů. Jedna preferuje co největší volnost v práci s datovými typy, druhá naopak co nejpřísnější pravidla. Jazyků bez typové kontroly je málo, stejně tak jazyků se zcela striktní kontrolou. Java se nachází v té přísnější oblasti, pravidla však nejsou až tak tuhá.
Jak známo, v Javě existují dva druhy datových typů: primitivní, a referenční.
Primitivních typů je jen několik, nemůžeme od nich odvozovat typy nové (něco
jako Primitivní typy
Tyto typy nesou pouze svoji hodnotu, podporují různé operátory pro operace
nad těmito typy, a jsou do jisté míry vzájemně přetypovatelné. Platí pravidlo,
že od typu s menším rozsahem nebo méně přesného k typu s větším rozsahem, resp.
přesnějšímu, můžeme provést implicitní přetypování, opačně nikoliv. Explicitně
lze přetypovávat i opačně. Pozor - typ Oproti např. jazyku C v Javě nikdy nevíme, jaké množství paměti ten který typ zabere - to je otázka implementace a na použití typu se to neprojeví. Co naopak známe, jsou meze rozsahu dat. Proto se můžeme vždy spolehnout, že určitý typ bude mít daný rozsah, bez ohledu na implementaci. Následující příklad ukazuje, jak s primitivními typy lze a nelze pracovat: int i = 10; // přiřazení hodnoty long l = i; // implicitní přetypování - lze byte b1 = l; // implicitní přetypování - nelze byte b2 = (byte) i; // explicitní přetypování - lze boolean f1 = i; // impl. přetypování na boolean - nelze boolean f2 = (boolean) i; // expl. přetypování na boolean - nelze double d = l; // implicitní přetypování - lze Referenční typy
Mezi referenční typy patří rozhraní, objektové třídy a pole.
Přistupuje se k nim zásadně pomocí referencí (které ale mají spíše charakter
ukazatelů). Při přiřazení hodnoty proměnné referenčního typu proto dojde vždy
k přiřazení reference (tzn. nová proměnná bude ukazovat na tentýž objekt jako
ta původní), nikoli hodnoty - pro předání hodnoty, tj. zkopírování objektu,
se musí použít buď kopírovací konstruktor (pokud ho třída poskytuje), anebo
klonování (pokud třída implementuje rozhraní Reference na hodnoty referenčních typů lze přetypovávat jen v případech, kdy jsou typy kompatibilní. Striktní typová kontrola vylučuje přetypování na nekompatibilní typy, bez ohledu na vnitřní datovou reprezentaci (oproti situaci v C++, kde si můžeme v tomto ohledu dělat prakticky cokoliv - samozřejmě na vlastní nebezpečí). Znamená to, že přetypování projde jen v těchto dvou situacích (přetypování na totožný typ vynechávám):
Podívejme se tedy, co je a co není v tomto ohledu legální: String s1 = "testovací objekt"; // lze - přetypování na nadtyp CharSequence cs = (CharSequence) s1; // lze - instance příslušného podtypu String s2 = (String) cs; // nelze - nekompatibilní typy // ohlásí kompilátor StringBuffer sb1 = (StringBuffer) s1; // nelze - instance nekompatibilního podtypu // vyhodí výjimku (viz dále) StringBuffer sb2 = (StringBuffer) cs; Výjimka ClassCastException
Již mnohokrát v tomto seriálu jsem upozorňoval na nutnost použití správného typu dat
- s tím, že nedodržení bude "potrestáno" výjimkou
Výjimky ArrayList<String> al = new ArrayList<String>(); al.add("text"); String s1 = (String) al.toArray()[0]; // funguje String sa1[] = (String[]) al.toArray(); // nelze! String s2 = (String) al.toArray(new String[0])[0]; // funguje String sa2[] = al.toArray(new String[0]); // správně
První možnost (pro někoho možná překvapivě) vyvolá výjimku Mám správnou instanci?
Kdo provádí operaci na datech, která získal odněkud "zvenku", a potřebuje
tato data přetypovat, musí si bezpodmínečně zjistit, že má správný typ.
Spoléhání na to, že "to vyjde", není dobré. A možná ještě horší je řešení
pomocí zachycování výjimky
Základním prostředkem pro zjištění správného typu je operátor URL url = new URL(urlString); // urlString máme odjinud URLConnection con = url.openConnection(); // otevře se spojení if (con instanceof HttpURLConnection) { // test typu instance // bezpečné přetypování HttpURLConnection hcon = (HttpURLConnection) con; ... } else { con.disconnect(); System.err.println("Toto není adresa protokolu HTTP"); ... } Tehdy jsem uvedl, že mlčky předpokládáme správný typ. Při adrese udané "natvrdo" v kódu to mohlo být použitelné (pro zkušební účely), ale obecně takové předpoklady dělat nesmíme. Zvlášť tehdy, má-li vliv na typ někdo jiný (např. uživatel, který někde zadá vstupní data). Kontrolu zkrátka nelze vynechávat. Třída Class
Každý referenční typ má v Javě má svoji instanci třídy URL url = new URL(urlString); // urlString máme odjinud URLConnection con = url.openConnection(); // otevře se spojení if (HttpURLConnection.class.isInstance(con)) { // test typu instance ... } if (con.getClass() == HttpURLConnection.class) { // test typu instance ... }
Zbývá ještě vyřešit, co kdy použít. Operátor Zjišťování informací
Třída
Vytváření tříd a instancí
Nejen zjišťovat informace můžeme pomocí třídy
Za normálních okolností vytváříme objekty zavoláním jejich konstruktoru nebo
nějaké metody, která instanci vytvoří (zavoláním neveřejného konstruktoru).
Existuje ale ještě další cesta, a tou je metoda Za normálních okolností lze již při startu rozhodnout, které třídy se mají načíst a inicializovat. Jsou to jednoduše ty, které se někde v programu používají. Někdy bychom ale potřebovali za běhu načíst nějakou třídu, která třeba při spuštění ani neexistovala. Typicky to může být třeba nějaký plugin (zásuvný modul). Ale i to je možné.
Třída try { Class c = Class.forName("MyDynamicClass"); // načtení třídy // lze přetypovat na Runnable? if (Runnable.class.isAssignableFrom(c)) { Runnable r = (Runnable) c.newInstance(); // vytvoření instance Thread t = new Thread(r); // použití t.start(); } } catch (Exception e) { System.err.println("Třída nebyla nalezena"); }
Příklad ukazuje, jak lze takto získaný objekt použít. Načteme třídu,
zjistíme, zda implementuje rozhraní Přístup odepřenNačítání tříd odněkud zvenku (ať už při startu nebo za běhu) skýtá poměrně velké nebezpečí. Do třídy totiž někdo může podstrčit nějaký nebezpečný kód, který snadno udělá v běžícím programu paseku - samozřejmě ale jen tehdy, pokud mu to dovolíme. Jak mu to nedovolit, tedy jak omezit oprávnění pro provádění různých potenciálně nebezpečných operací, si vyzkoušíme příště. Jen naťuknu, že takové mechanismy se používají např. ve webových prohlížečích, aby applety ze sítě nemohly sahat na lokální disk nebo dělat jiné zapovězené věci.
|
Search Software
Search Google
|
||||||||||||||||||||||||||||||||||||||||||||||
©Pavel Kysilka - 2003-2024 | maillinuxsoft.cz | Design: www.megadesign.cz |