Üdvözlök mindenkit a ProgHu Java rovatában mely újra jelentkezik. Az előző Java számban volt, akinek nem ment a ProgHu-s (PC-X User-es) példa applet. Hát igen, JDK1.1-et támogató browser-t kell használni úgy, mint pl. a Netscape Communicator 4.5 (vagy 4.06+). Annál is inkább ajánlott egy JDK1.1-et alapból támogató browser, mert nem rég megjelent a JDK1.2 (Java2.0) mely meggyorsítja a JDK1.1 széleskörű elterjedését. Na de nem untatlak benneteket, inkább nézzünk valami olyat, ami még nem volt, s ami hasznos lehet. Beszélgessünk a java.lang csomagról.

A java.lang csomag

A java.lang csomag abszolút alapvető típusokat tartalmaz. Feltűnő, hogy soha sem importáltuk, bár használtunk előző cikkeink során a benne definiált típusok közül néhányat. Ennek oka, hogy automatikusan importálódik, jelentősségénél fogva. Bizonyos típusok e csomagból mindenképen használtak, még akkor is, ha mi semmit sem használunk belőle, pl. a Runtime típus. A másik eset ha string-ekkel végzünk műveleteket, (akár konkrét string definiálása nélkül) akkor is felhasználódnak bizonyos osztályok, pl. a:

System.out.println("Prog"+"Hu");

esetén.
 

Az Object osztály

Az Object osztály minden osztály közös őse, a hierarchia tetején áll. Ha nem adunk meg egy definiált osztálynak őst, akkor az, az Object osztályból örökítődik. Így mivel minden objektum közös őse az Object osztály, minden osztály rendelkezik az Object osztály metódusaival. Lássuk az Object osztály metódusait: 

  • clone() - Adott - s sad - osztállyal megegyező típusú új példányt hoz létre
  • equals(Object) - Összehasonlít két osztályt, hogy egyenlőek -e. Elvileg akkor egyenlőek, ha referenciáik megegyeznek, de a gyakorlatban el is térhetnek, mint majd később láthatjuk.

  • finalize() - A szemétgyüjtő (garbage collector) hívja meg, ha már nincs egyetlen hivatkozás sem az objektumra. Ez a megsemmisítés előtt hívódik meg.
  • getClass() - Visszaadja a futásidejű (dinamikus) osztályát az objektumnak.
  • hashCode() - Visszaadja az objektum hashkód értékét.

    • Valahányszor meghívjuk ugyanazon az objektum hashCode() metódusát az applet / applikáció futása során mindig ugyanazon integer-t kell visszaadnia.

    • Ha két objektum egyenlő az equals() metódus szerint, akkor a hashCode() metódus által szolgáltatott értékeknek is meg kell egyezniük.

  • notify(), notifyAll() - Egy, ill. az összes thread felkeltése. Ezek a metódusok nem felülírhatóak. A párhuzamosságnál használjuk őket.

  • toString() - Az objektumot string-ként reprezentálja. (Visszaadja nevét string-ként.) Ezt a metódust illik minden új osztály definíciója során felülírni, hogy a megfelelő értéket reprezentálhassa.

  • wait(),wait(long), wait(long, int) - Egy másik thread-re (szálra) vár, hogy figyelmeztessen, hogy megváltozott az objektum. Ez a metódus se írható felűl.

Az elemi típusok és a hozzájuk tartozó osztályok

A Java előnyei között tarthatjuk nyilván, hogy csak objektum orientáltan lehet benne programozni. Így áttekinthetőbb, modulárisabb, könnyebben bővíthető kód hozható létre. Nem létezik objektumon kívüli se, változó se rutin, tehát minden objektumokból áll. Ez alól kivételt képeznek az elemi típusok, melyek nem osztályok. Az elemi típusok az alapvető numerikus számításokhoz használatosak. Minden elemi típusnak meg van az osztályszintű megfelelője. Amennyiben csak számolásra használjuk az elemi típusokat, akkor a fordító nem jelez hibát. Viszont más egyéb használat során, pl. amikor egy numerikus alaptípust használunk, amikor a neki megfelelő osztályt kellene használni, akkor a fordító hibát jelez.

Erre láthatunk egy példát az alábbiakban. A java.util csomagban van a vermet létrehozó Stack osztály. A veremnek van push() és pop() metódusa. A metódusok Object() osztályú paramétereket várnak. Tehát a verembe bármilyen típusú (objektumot) elhelyezhetünk. A gond csak az, hogy mi egy sima alaptípusból, pl. int egészből álló vermet szeretnénk készíteni. Az alábbi példa bemutatja a hibás alkalmazást:

    import java.util.Stack;public class Stackpelda {   public static void main(String args[]) {     Stack       s = new Stack();     int         i = 3, j;     Integer     ii = new Integer(i);     Integer     jj; //    s.push(i);               //Rossz !!!
    //    j = s.pop();             //Rossz !!!
        s.push(ii);     jj = (Integer)s.pop();     j = jj.intValue();     System.out.println(j);  } }
     

A programban a jelzett hiba egyszerűen az, hogy az elemi típusok nem osztályok, így nem használhatók olyan paraméterként, ahol osztályt várnak el. Létre kell hoznunk az elemi típusnak megfelelő osztályú objektumot, s az objektummal kell megadni paraméterként a kívánt egész értékeket. Minden elemi típusnak van osztály szintű megfelelője, ezeket kell ilyenkor használni. Lássuk az elemi típusok osztály szintű megfelelőjét:
 

byte
č
Byte
short
č
Short
int
č
Integer
long
č
Long
float
č
Float
double
č
Double
char
č
Character
boolean
č
Boolean
void
č
Void

Így látható, hogy az int elemi típusnak megfelelő Integer() osztályt kell használnunk. A kérdés az-az, hogy milyen konstruktora, milyen metódusai vannak az elemi típusoknak megfelelő osztályoknak.
 

Az Integer osztály

A fenti példának megfelelően az Integer osztállyal ismerkedjünk meg. Minden elemi típusnak megfelelő osztálynak megvannak a hasonló (csak más nevű) metódusai. Lássuk a példa beli inicializáláshoz szükséges konstruktort:

  • Integer ii = new Integer(i);

Ez a konstruktor egy int elemi típusú paramétert vár, és a konstruktorban az Integer objektum a value mezőjébe másolja (Integer.value=paraméter_int;//Ez egy képletes megadás) Így 'konvertálódik' át a primitív alap típus értéke egy objektummá (annak értékévé). A fenti példában az ii objektum létrehozása azért történt így, mert rögtön inicializáltuk is. Deklarálhattuk volna csak az ii referenciát (Integer ii;), s később is rendelhettünk volna hozzá egy új objektumot (ii = new Integer(i);). Az Integer osztálynak van egy másik konstruktora is:

  • Integer(String)

Ez a bemeneti string-ből állítja elő az Integer objektum értékét. Amennyiben a string nem (csak) számot tartalmaz, pontosabban hibás a szám megadása, akkor NumberFormatException kivétel generálódik.
 

Konverziók

Ahhoz, hogy String-et int-té konvertáljuk nem kell új objektumot létrehoznunk, s konstruktorban megadni az átalakítandó String-et, hanem megoldható a parseInt() metódussal is.

  • int i = Integer.parseInt("12345");
  • int j = Integer.parseInt("ABCD", 16);

Az első esetben (alapértelmezés szerinti parseInt() metódus) a String-ben megadott számot a tízes számrendszer szerint adja vissza. A String-ben nem lehet semmi a számon kívül, kivéve az első pozícióban a - jel. A második felülírása a metódusnak már megköveteli a második paramétert a számrendszer megadását. Esetünkben megadtuk, hogy 16-os (hexadecimális) számrendszerben értelmezze a String-et. Így e szerint alakítja a j int-té a String-et. Amennyiben a String vagy nem megfelelő karaktert, vagy a számrendszernek nem megfelelő számjegyet tartalmaz (pl. binárisban: 2-t) akkor, NumberFormatException kivétel generálódik.

Ha int-et (vagy Integer-t) akarunk String-gé konvertálni akkor azt újfent két féle módon tehetjük meg. Vagy az Integer osztály toString()metódusával akkor amikor az Integer objektum már tartalmazza az átalakítandó értéket, vagy közvetlenül a toString() metódusnak adjuk az átalakítandó értéket.

1.
    Integer i = new Integer(1234); String Str = i.toString();
2.
    String Str = Integer.toString(1234);

Természetesen itt is van olyan toString() metódus mely lehetőséget biztosít a számrendszerek használatára:

3.
    String Str = Integer.toString(256, 2);
A leggyakoribb számrendszerekhez készítettek saját konvertáló metódust:
    String s1 = Integer.toBinaryString(256); //kettes számrendszer String s2 = Integer.toOctalString(256); //nyolcas számrendszer String s3 = Integer.toHexString(256); //tizenhatos számrendszer

A legelső példában szerepel az intValue() metódus mely az objektum értékét int típusban adja vissza. Hasonlóan léteznek a többi típusra is megfelelő metódusok.
 

Az érték lekérdezése

Az objektum értékét az alábbi típusokra konvertálva kaphatjuk meg:

    byte   byteValue(); double doubleValue(); float  floatValue(); int    intValue(); long   longValue(); short  shortValue();
A hat metódust a Number osztály definiálja, így minden elemi típusnak megfelelő osztály tartalmazza.

Az értékek megadásánál és lekérdezésénél hasznosak lehetnek a numerikus konstansok melyek megadják akár az elemi típusokkal akár a nekik megfelelő objektumokkal kezelhető legkisebb és legnagyobb számokat. Pl. az Integer() osztály esetén a legkisebb kezelhető szám az Integer.MIN_VALUE és a legnagyobb kezelhető szám pedig az Integer.MAX_VALUE. Ezek a konstansok minden számnál megtalálhatóak így a Long, Double, ... osztályok esetében is. A nem egész számok esetén használatos típusoknál a Double és Float típusoknál viszont a konstansoknak más jelentése van. Míg az Integer, ill. Long típusnál a MIN_VALUE a legkisebb ábrázolható negatív számot adja vissza, itt a Double, ill. Float típusoknál a legkisebb ábrázolható pozitív számot jelöli a MIN_VALUE. A MAX_VALUE értelmezése megegyezik. Ezeknél a lebegőpontosan ábrázolt számtípusoknál azonban van még egy konstans, ami a koprocesszor NaN kifejezését reprezentálja. A NaN (Not a Number) azt jelenti, hogy hibás a lebegőpontos szám megadása. Mivel a Double.NaN nem szám, nem egyezhet meg értéke egyetlen más Double számmal sem, beleértve a önmagát is, így a Double.NaN == Double.NaN is hamis értéket ad vissza. A Double és Float típusnak vannak további konstansai is melyek a mínusz és plusz végtelent reprezentálják: NEGATIVE_INFINITY, POSITIVE_INFINITY). A char elemi típusnak is értelmezett a MIN_VALUE konstansa, értéke Unicode-ban: '\u0000' és a MAX_VALUE konstansa is, értéke: '\uFFFF'.
 

Az int típusú rendszerjellemzők lekérdezése

A Java-ban az alábbi rendszerjellemzők biztosan deklarálva vannak:

java.version
A Java verziószáma
java.vendor
Java fejlesztő neve
java.vendor.url
Java fejlesztő URL-je
java.home
Az elérési útvonal ahova a Java-t felinstalláltuk
java.class.version
Java class verziószáma
java.class.path
Java classpath (a class-ok elérési útvonala)
os.name
Az operációs rendszer neve
os.arch
Az operációs rendszer architektúrája
os.version
Az operációs rendszer verziószáma
file.separator
File elválasztó az útvonalban (pl. Unix "/")
path.separator
Útvonal elválasztó (pl. Unix ":")
line.separator
Újsor karakter (pl. Unix "\n")
user.name
A felhasználó neve
user.home
A felhasználó home könyvtára
user.dir
A felhasználó aktuális könyvtára

Ezek közül az Integer típusú rendszerjellemzőket a getInteger() metódussal kérdezhetjük le. Amennyiben nem Integer típusú rendszerjellemzőt kérdeztünk le akkor null-t ad vissza, vagy a második paraméterként megadott számot:

  • Integer i = Integer.getInteger("java.version");
  • Integer j = Integer.getInteger("java.home"); //hiba esetén null-t ad vissza
  • Integer k = Integer.getInteger("java.home", 256); //hiba esetén 256-ot ad vissza
String-ek

Programjaink nagy részében szükség van karakteres információk eltárolására. Sok programozási nyelv támogatja a karakterfüzéreket. Vannak bizonyos nyelvek melyek nem támogatják konkrét módon, de használhatóak más egyszerű típusok e célra, ilyen nyelv a C. Ebben az esetben viszont vigyáznunk kell, hogy a lefoglalt hely a karakterlánc számára, pl. a char* típussal megfelelő hosszú legyen, nehogy túlírjunk a változón. Java-ban a C-től eltérően van kialakított karakterlánc típus a String típus. A string kezeléssel kapcsolatos teendőket a String és StringBuffer osztályok oldják meg.
 

A String osztály

A String osztály konstans string-eket tud kezelni, az-az statikus a létrehozott string nem módosítható (dinamikusan) a létrehozás után a mérete. A String osztály a karakterláncot (string-et) egy karakter tömbben és hosszát egy számban tárolja. Ha a string-ben nem létező indexű karaktert akarunk elérni StringBufferOutOfBoundsException generálódik. Ebben legalább az a jó a többi nyelvtől eltérően, hogy biztosan tudomást szerzünk a bekövetkezett hibáról.
 

String-ek létrehozása

A String-et a szokásos new kulcsszóval hozhatjuk létre, s konstruktorával inicializálhatjuk. Az inicializációnak sok módja van:

  • String S1 = new String();

  • Szerény eset, de nem lesz értéke. 
  • String S2 = new String("ProgHu");

  • Egy sima karakterlánccal inicializáljuk.
  • String S3 = new String("Ez a "+S2+24+". száma");

  • Ez már szebb inicializálás, először is rész string-ekből is összefűzhető, mely lehet idézőjel között, de lehet másik string is. A 24-es számot nyogodtan beírhatjuk a paramétersorba, ugyanis automatikusan meghí 

A string-ek inicializálására van egyszerűbb mód is mikor nem hívjuk meg explicit módon a new operátort, s az String osztály konstruktorát. Az implicit létrehozás automatikusan meghívja a konstruktort. Így a fenti műveletek egyszerűbben is elvégezhetőek:

  • String S1 = "";
  • String S2 = "ProgHu";
  • String S3 = "Ez a "+S2+24+". száma";

Továbbá lehetőségünk van karaktertömbből is inicializálni a String-et. Pl.:

  • char data[] = {'P', 'C', '-', 'X'};
  • String S4 = new String(data);
  • String S5 = new String(data, 2, 2);

Az első esetben (S4 String) az egész karaktertömbből készíti el a String-et, míg a másodikban csak a 2. karaktertől kezdve másol két karaktert a String-be.

Nem csak char tömbből, hanem byte tömbből is lehet String-et készíteni. Ennek az az előnye, hogy megadható milyen kódolás szerint adjon a tömbből a String-nek értéket. Lássunk egy példát:

    byte data[] = {65, 66, 67, 68, 69}; String S6 = new String(data);try {   String S7 = new String(data, 2, 3, "8859_2");   // ... } catch (Exception e) {   System.out.println("Ismeretlen kódolás"); }

Először definiáljuk a byte tömböt, majd az S6 String-nél nem adunk meg kódolást, így az alapértelmezett kódolással történik a konverzió. Az S7 String-et az ISO-LATIN-8859_2 kódolással alakítjuk át. Ez a Közép Európai kódolás. Ha ismeretlen kódolást adnánk meg akkor, kivétel generálódik, s példánkban kiíródik. Elég sok kódolási típus definiált a sun.io.* csomagban. Itt például megtalálható a számunkra leginkább használható "Cp852"-es kódolás, vagy a Windows alapértelmezett kódolása a "Cp1250", vagy akár Unicode-ból is konvertálhatunk. Az S6 String értéke "ABCDE" lesz, míg az S7-é "CDE" lesz, mivel csak a 2. byte-tól 3 byte-on keresztül történt a konvertálás.
 

Konverziók

Tetszőleges típusú objektumok is átalakíthatóak String-gé a valueOf() metódus segítségével. A beépített alaptípusok (boolean, char, double, float, int, long, char[]) biztosan átkonvertálhatóak, míg egyéb típusok nem biztosan. A valueOf() metódus vagy egy Object() típusú paramétert vár vagy a fent megnevezett primitív (alap) típusokat. Az objektumok String-gé konvertálása attól függ, hogy az objektum toString() metódusa megfelelően át lett e írva az új objektumhoz. Ha a valueOf() metódusban null referenciát adunk meg akkor ezt adja vissza string-ként, ellenkező esetben pedig meghívja az objektum toString() metódusát, s ez alapján ad vissza nevet. Saját, új osztály definiálásakor vigyázni kell arra, hogy mindig megfelelően felülbíráljuk a toString() metódust.

boolean bool = false; int d = 3; String S9 = String.valueOf(2) + String.valueOf("=") + String.valueOf(d) + String.valueOf(bool)

Hatására a "2=3false" String jön létre. A valueOf() metódusnak van tartománya, hogy x. karaktertől y-on keresztül végezze a konvertálást char[], vagy egyéb String-ből.

Van egy visszafelé működő metódus, mely a String-ből készít char[]-t (karaktertömböt) ez a toCharArray() metódus. Pl.:

    char data[] = S1.toCharArray();
     
String karaktereinek lekérdezése, vizsgálata

Ha leakarjuk kérdezni egy String adott karakterét akkor ezt a CharAt() metódussal tehetjük meg. Pl.:

    char c = S1.CharAt(3);

Ha két String-et kívánunk összehasonlítani, hogy megegyeznek -e, annak két egyszerűbb módja van, az egyik mikor figyelembe vesszük a kis és nagy karakterek különbözőségét: equals() metódus, és amikor figyelmen kívül hagyjuk: equalsIgnoreCase() metódus. Pl.:

    boolean b1 = "ProgHu".equals("proghu"); boolean b2 = "ProgHu".equalsIgnoreCase("proghu");

Az első esetben hamis értéket kapunk, hisz itt teljes összehasonlítás történik karakterről, karakterre, míg a második esetben pedig igazat, mert a kis és nagy betűk közötti különbség nem számít.

Abban az esetben, ha meg akarjuk tudni, hogy két egyenlő String közül melyik String van előrébb a másikhoz képest az abc-ben, akkor a compareTo()metódus használatos mely int értéket ad vissza. A visszaadott egész érték 0 ha a két String teljesen egyforma, negatív ha hívott (első, ami után a .compareTo() van) String kisebb, s pozitívat ha a második a kisebb (a metódus paramétereként megadott String). A visszaadott érték azt is megmutatja, hogy hol van az (első) eltérés a két String között. A regionMatches() metódusnál megtehetjük, hogy csak egy részét hasonlítsuk össze a két String-nek, s ott is megadhatjuk, hogy a kis és nagy betűk között különbséget tegyen -e. Pl.:

boolean b3 = "ProgHu".regionMatches(1, "PfogHu", 1, 3); boolean b4 = "ProgHu".regionMatches(true, 1, "pfogHu", 1, 3);

Első példánkban az 1-es karakter jelenti, hogy a meghívott String 1-es karakterétől, a paraméterben megadott String 1-es karakterétől (utolsó előtti paraméter) 3 karakteren keresztül (utolsó paraméter) történjen az összehasonlítás. A String-ben a karakterek számozása 0-tól kezdődik !!! A második példa első paramétere a boolean érték jelenti, hogy figyelmen kívül hagyja -e a kis és nagy betűk különbözőségét.

Szükségünk lehet megkeresni, hogy egy karakterlánc megtalálható -e, s ha igen akkor hol található meg az adott String-ben. A keresés közül a legegyszerűbb az indexOf() metódus használata. A metódus int értéket ad vissza, hogy hol található meg a karakter, vagy karakterlánc a String-ben. Itt is 0-tól számozottak a karakterek, s -1 a visszaadott érték ha nem fordul elő a keresett karakter vagy karakterlánc. Pl.:

    int index1 = "ProgHu".indexOf("uHgorP"); int index2 = "ProgHu".indexOf("Hu", 2);

Az index1 értéke -1 lesz hisz nincs benne, az index2 értéke pedig 5. A keresést ez esetben a második karaktertől kezdtük.

Ha kíváncsiak vagyunk egy karakter avagy karakterlánc utolsó előfordulására, akkor a lastIndexOf() metódus használható. Pl.:

    int index3 = "ProgHu Java rovat".indexOf("va"); int index4 = "ProgHu Java rovat".lastIndexOf("va", 2);

Az index3 értéke 12 lesz hisz ott található meg először, míg az index4 értéke pedig 17 lesz hisz ott található meg másodszor. Itt is használható a paraméter, hogy honnan kezdjük a keresést.

Utolsó vizsgálódásunk segít megmutatni, hogy adott karakterrel, vagy karakterlánccal kezdődik vagy végződik -e egy String.

    boolean b5 = "ProgHu Java".startsWith("ProgHu"); boolean b6 = "Prog Java".endsWith("Java");
String-ekkel kapcsolatos egyéb műveletek
  • A String hosszát a length() metódus adja vissza.
  • A String-et csak nagybetűssé alakíthatjuk az toUpperCase() metódussal, míg csak kisbetűssé a toLowerCase() metódussal.
    String S10 = "kicsiből lesz a nagy".toUpperCase(); String S11 = "és NAGYBÓL lesz a kicsi".toLowerCase();
  • Szükséges lehet egy String-ben adott karakterek kicserélésére, a replace() metódussal tehető meg:
    String S12 = "Jbvb".replace('b', 'a'); //S visszakapjuk a Java String-et.
  • A String-ek elejéről, s végéről a szóközt levágó metódus a QBasic-ből jól ismert trim() metódus.
    String S13 = " ProgHu ".trim();
  • A String-ból egy karakterláncot a substring() metódussal másolhatunk ki.
    String S14 = "ProgHu".substring(1, 4);
    Így a 1. karaktertől a 4. karakterig másolunk ki, így kapjuk az "Prog" String-et.
     
  • Két String összefűzését a concat() metódussal tehetjük meg.

  •  

     

    String S15 = "Prog".concat("Hu");
    Így kapjuk a "ProgHu" String-et.
     

Nos végetért a variációk a "ProgHu" témára című nótánk, s annyit tennék még hozzá, hogy a StringBuffer osztály leírását a párhuzamos környezetek leírásakor részletezzük. A java.lang.* csomagot szerintem a szükséges mértékben részleteztük, így következő számunkban talán már új (eddig nem tárgyalt) AWT komponensekről, vagy a párhuzamos környezet használatáról beszélgetünk.



Felhasznált irodalom:
     
    [1]   JDK 1.1.2 ™ Documentation, Copyright Š 1996, 1997 Sun Microsystems, Inc.
    [2]   Java 1.1 útikalauz programozóknak, Nyékyné Gaizler Judit
    (Köszönet a könyvnek a példákért, a logikus magyarázatokért, melynek segítségével tanultam / tanulok én is. Igazán jó könyv. Érdemes fellapozni.)