1.1. Ievads

Javas Tehnoloģijas

Mērķi

  • Raksturot Java tehnoloģijas īpatnības
  • Definēt jēdzienus klase (class) un aplikācija (application)
  • Izveidot, nokompilēt un palaist vienkāršu Javas aplikāciju
  • Aprakstīt Javas virtuālās mašīnas (JVM) funkcijas
  • Aprakstīt drazu savākšanu (garbage collection)
  • Aprakstīt Javas platformas darbības saistībā ar programmu izpildes drošību

Kas ir Javas tehnoloģija?

Javas tehnoloģijā ietilpst:

  • Javas Programmēšanas valoda
  • Javas standarta API un citas bibliotēkas
  • Izstrādes vide un rīki. Piemēram, kompilēšanai (rīks javac), CLASS koda interpretēšanai (java), dokumentācijas ģenerēšanai (javadoc), klašu failu arhivēšanai (jar), u.c.
  • Aplikāciju darbināšanas vide (Java Runtime Environment) - patstāvīgām programmām (standalone program), apletiem, servletiem, utml.

Javas valodas īpatnības

Saskaņā ar Sun Microsystems aprakstu: Java: A simple, object-oriented, network-savvy, interpreted, robust, secure, architecture neutral, portable, high-performance, multithreaded, dynamic language. (Sk. http://java.sun.com/docs/overviews/java/java-overview-1.html). Var piebilst arī, ka Java ir cieši saistīta ar atvērtā koda izstrādi - Javas tehnologjiju uzvedību nosaka publiskoti, relatīvi vienkārši standarti - šos standartus var uzprogrammēt ikviens, kurš to vēlas (tādēļ ir daudz bezmaksas un atvērtā koda rīku). Javā turklāt bieži raksta visdažādāko "open source" programmatūru.

  • Vienkārša (<simple>) Veiksmīgs kompromiss starp koda īsumu un lasāmību
  • Objektorientēta (<object-oriented>) Viss kods strikti dalās pakotnēs un klasēs. Izņemot 8 primitīvos tipus (int, boolean, u.c.) visi dati ir objektveidīgi. Daudzkāršā mantošana, nevirtuāla metožu mantošana, "draugu klases" u.c. problemātiski objektorientācijas mehānismi no C++ nav pārgājuši uz Javu.
  • Tīklorientēta (<network-savvy>) Resursus (datus, kodu) viegli savākt tīklā. Viegli radīt klienta/servera vai daudzslāņu aplikācijas (multi-tier application).
  • Interpretēta (<interpreted>) Interpretējamība veicina: (1) izstrādes ātrumu (pēc katras izmaiņas nav jāatkārto pilns kompilācijas/linkošanas/ielādes/testēšanas cikls). (2) Koda pārnesamību (programmu var darbināt uz jebkuras specifikācijai atbilstošas JVM). (3) Drošību (interpretators, atšķirībā no datora dzelžiem, var labāk pārbaudīt, vai kods nedara ko neatļautu.)
  • Izturīga valoda (<robust language>) Programmētāja kļūdas un citas neparedzētas situācijas izraisa Javas izņēmumus (piemēram, mēgjinājums rakstīt ārpus masīva robežām, ko C++ kods nekontrolē). Izņēmumus var ķert un apstrādāt pats programmētājs vai arī tie aptur atbilstošo izpildes pavedienu un var redzēt kļūdu radījušo izsaukumu steku.
  • Droša valoda (<secure language>) Java platforma var izpildīt neuzticamus apletus un citu kodu, to darbinot Javas interpretatora smilšukastē. Javas servletu gadījumā Web servera administrators var konfigurēt katrai aplikācijai atļauto drošības politiku - kādus failus programma drīkst rakstīt un lasīt, kādas tīklošanās darbības veikt.
  • Platformneatkarīga valoda (<architecture neutral language>) Javas programmu sakompilēto starpformātu (.CLASS failus) var darbināt uz visām platformām, uz kurām ir Javas interpretators. Sun lozungs: Write once, run anywhere.
  • Ātrdarbīga valoda (<high-performance>) Lai gan uz platformatkarīgu kodu kompilēts kods (piemēram, no C++ iegūti izpildāmi faili) parasti pildās daudz ātrāk, Javas programmas darbojas pietiekami ātri, ja ir pietiekami atmiņas virtuālajai mašīnai. Koda ātrai izpildei var palīdzēt arī JIT (Just in Time) kompilators.
  • Daudzpavedienu valoda (<multithreaded>) Javā programmētājam viegli programmēt visdažādāko daudzpavedienu kodu.
  • Dinamiska valoda (<dynamic language>) Klases ielādē izpildes laikā. Komponentes programmas izpildei var savākt arī, teiksim, Internetā. Web aplikācijās tātad viegli nomainīt izmantojamos datubāzu draiverus un citas palīgbibliotēkas.

Javas Virtuālā Mašīna (JVM)

Javas Virtuālās Mašīnas raksturojums

  • "Aparatūras" specifikācija .CLASS failu izpildei; to emulē ar programmnodrošinājumu; t.i. nav vajadzīgs, lai mašīnas "dzelži" saprastu Javas CLASS failus.
  • JVM lasa kompilēto baitkodu (.CLASS failus), kas ir platformneatkarīgs
  • Var būt Javas izstrādes vides (piem. JDK1.4) sastāvdaļa, Javas izpildes vides (JRE) sastāvdaļa, vai pārlūkprogrammas spraudnis jeb plugins.
  • No tipu pārbaudēm lielākā daļa veikta kompilācijas laikā (stipri tipizēta valoda - mainīgo tipi ir zināmi kompilācijas laikā; ir tomēr iespējams polimorfisms).
  • Jebkurai Sun Microsystems apstiprinātai JVM jāvar darbināt jebkurš standartam atbilstošs .class fails.

Javas Virtuālās Mašīnas sastāvdaļas

  • Instrukciju saraksts JVM procesoram (CPU)
  • Reģistri
  • .class failu formāts
  • Aktivāciju steks
  • Atmiņas rezervēšanas kaudze (memory allocation heap) ar drazu savācēju
  • Atmiņas apgabals

Drazu savākšana

  • Dinamiski piešķirtā atmiņa (dynamically allocated memory), uz kuru vairs nenorāda mainīgie izsaukumu stekā, ir kļuvusi nepieejama, to vajag pamazām atbrīvot (to deallocate).
    public class A {
        public String f() {
            String a1 = "Hello";
            String b1 = "BB";
            String b2 = "BB";
            a1 = a1 + "!"; 
            // Stringa objekts "Hello" nupat kļuva par drazu, 
            // jo mainīgais "a1" norāda uz jaunu objektu - "Hello!"
            b1 = null;
            // Stringa objekts "BB" nav draza, jo uz to joprojām 
            // norāda mainīgais b1
            return a1;
            // pēc iziešanas no šīs metodes, "BB" kļūst par drazu, 
            // jo izpildes stekā vairs nav mainīgā "b2". 
            // Toties objekts "Hello1" joprojām dzīvo - to 
            // 
        }
    
        public static void main(String[] args) {
            A a = new A(); // izveido jaunu klases A eksemplāru
            System.out.println(f()); // drukā "Hello1". 
            // pēc iziešanas no šīs metodes arī klases A 
            // vienīgais eksemplārs un strings "Hello1" būs drazas
        }
    }
    
  • Daudzās valodās par atmiņas atbrīvošanu atbild programmētājs (t.sk. valodā C++ ir jāraksta komandas "delete p", lai atbrīvotu pointeri, pirms tas kļūst nepieejams vai nevajadzīgs).
  • JVM ir sistēmas līmeņa pavediens, kurš seko atmiņas atbrīvošanai, t.i. programmētājs par to neatbild.

Drazu savākšana:

  • Konstatē vairs nevajadzīgo atmiņu un to atbrīvo.
  • To veic automātiski.
  • Dažādās JVM drazu savākšana var būtiski atšķirties. Programmētājs var ierosināt drazu savākšanu (teiksim, ja programmas izpildē gaidāma pauze), rakstot šādu komandu:
    vairsNevajadzigsMainigais = null; 
    // atbrīvo objektu, uz kuru norādīja vairsNevajadzigsMainigais
    Runtime.getRuntime().gc();
    // Programmētājs ierosina JVMam veikt drazu savākšanu 
    

    Bet neviens no šiem paņēmieniem negarantē, ka drazas tiešām tiks savāktas pirms programmas izpilde turpināsies tālāk.

Klašu ielādētājs (classloader)

Nodrošina programmu koda drošu izpildi. Klašu ielādētājs un bitkoda pārbaudītājs noskaidro, vai bitkods ir pareizi izveidots. Tālāk to izpilda vienā no 2 veidiem:

  1. Ar interpretatoru jeb JVM, kas bitkodu pārvērš platformatkarīgās instrukcijās rindiņu pa rindiņai.
  2. Efektīvāka ir koda ģenerācija "pēc pieprasījuma" (JIT, just-in-time) - t.i. JIT kompilators "atceras", kuri Javas bitkoda gabali jau ir iztulkoti platformatkarīgās instrukcijās un netulko tos vēlreiz.
  3. Trešā iespēja būtu Javas kodu uzreiz kompilēt par platformatkarīgām instrukcijām - tāpat kā C vai C++. Tas strādātu ātrāk gan par JVM, gan par JIT. Bet šajā gadījumā zustu vairākas Javas platformas priekšrocības, t.sk. koda izpildes lielāka drošība.
Izpildes vide JVM un JIT gadījumā

Sk. piezīmi - The Byte Code Verification Process. Lai gan JIT kompilatoru lietošana var paātrināt koda izpildi līdz pat 10 reizēm, bieži lieto interpretāciju ar JVM, jo programmas gan tiek pildītas lēni, bet JVM parasti ir mazākas prasības pret dzelžiem un tas ātrāk ielādējas. Sun Microsystems piedāvā populāru kombinētu risinājumu HotSpot, kam ir gan JVM, gan JIT iespējas.

Javas izpildes laika vides funkcijas:

  • Ielādē, pārbauda, izpilda bitkodu
  • Rekursīvi sekojot koda atkarībām, ielādē visas klases, kuras nepieciešamas programmas izpildei
  • Klases, kuras nāk no vietējās failu sistēmas (local file system) glabājas atsevišķos vārdapgabalos (namespace).
  • Nepieļauj viltošanas (spoofing) uzbrukumus

Viltošanas uzbrukumi ir mēģinājums iesūtīt ļaunprātīgi modificētus datus tādā vietā, kurai saņēmējs uzticas un šādi izprovocēt saņēmēju veikt uzbrucējam vēlamās darbības. Javas apletu gadījumā - no Interneta atnākušais kods varētu vēlēties nonākt "uzticamā" JVM apgabalā un izpildīties kā droša programma ("Trojas zirgs" utml.). Javas platforma šādus uzbrukumus novērš. (Ir arī "spoofing"-am līdzīgs termins - sniffing, t.i. tīkla saziņas noklausīšanās, to nemodificējot.)

Baitkoda pārbaudītāja (bytecode verifier) funkcijas

  • Vai CLASS failu kods kods atbilst JVM specifikācijai
  • Vai kods nepārkāpj Javas izejas kodā noteiktos ierobežojumus (piekļuves pārkāpumi: piemēram, mēgjinājumi no ārpuses izsaukt funkciju, kas deklarēta kā "private" - var būt bīstami, it īpaši ja ļaunprātīgs kods neparedzētā veidā izsauc metodes citu autoru programmētām klasēm).
  • Vai kods pareizi izmanto izteiksmju operandu steku (t.i. nenotiek steka pārpildīšanās vai iztukšošanās)
  • Vai metožu izsaukumiem nododamo aktuālo parametru tipi ir pareizi
  • Nenotiek neatļauti datu pārveidojumi (veselo skaitļu tipi uz referenču tipiem, utml.)

Piezīme: Kas ir formālie parametri (formal parameters) un kas ir aktuālie parametri (actual parameters)? Piemērs:

// Metodes rindiņu līdz atverošajai figūriekavai 
// sauc par prototipu. 
// Metodes prototipā ierakstītie parametri a un b 
// ir formālie parametri. 
public int sum(int a, int b) {
    return a+b;
}

// Šajā sum() izsaukuma piemērā 3 un 4 ir aktuālie parametri
public void f() { 
    System.out.println(sum(3,4))
}

Piemēri

Vienkārša Javas aplikācija

ClockMain.java

package sample1;

public class ClockMain {
    public static void main(String[] args) {
        MyClock myClock = new MyClock();
        System.out.println(myClock.getMessage());
    }
}

MyClock.java

package sample1;

import java.util.Date;

public class MyClock {
    public String getMessage() {
        Date d = new Date();
        return "Pareizs laiks: " + d;
    }
}

Kā kompilēt un palaist ClockMain konsoles aplikāciju:

javac ClockMain.java
java ClockMain

(MyClock.java kompilējas automātiski)

  • Ja ir kompilācijas vai izpildes kļūdas, procesu var atkārtot

    Visas klases pārkompilēt var ar komandu:

    javac *.java
    

    Lai varētu kompilēt, atkļūdot (debug) Javas programmas, vajag izpildīšanas vidi, kompilatoru (javac), interpretatoru (java) un citus programmatūras rīkus. To sauc par Javas programmēšanas instrumentāriju: JDK (Java Developer Kit).

    Uzinstalējot šo JDK, piemēram, uz Windows datora direktorijā c:\Program Files\Java\jdk1.6.0, Javas Virtuālā Mašīna ir izpildāma programma "jdk1.6.0" apakšdirektorijā bin/java.exe, un Javas kompilators ir cita izpildāma programma šajā apakšdirektorijā - bin/javac.exe. Tādēļ, lai Javu varētu gan kompilēt, gan darbināt jebkurā direktorijā, ir ieteicams definēt sistēmas vides mainīgo JAVA_HOME ar vērtību c:\Program Files\Java\jdk1.6.0 (vai jebkuru citu, kuru esat izvēlējušies instalācijas brīdī), kā arī pievienot PATH mainīgajam direktoriju %JAVA_HOME%/bin (PATH direktorijas uz Windows datoriem atdala ar semikoliem(;)). Šajā gadījumā, kompilējot un darbinot Javas programmas nebūs jānorāda pilns ceļš uz javac un java.

Kompilācijas laika kļūdas

  • javac: Command not found
    
  • ClockMain.java:6: cannot resolve symbol
    symbol  : method printl  (java.lang.String) 
    location: class java.io.PrintStream
    System.out.printl(myClock.getMessage());
                     ^
    
  • NotClockMain.java:4: Public class ClockMain must be defined in a file called "ClockMain.java".
    
  • %JAVA_HOME%/bin direktorijai (tur atrodas kompilācijas utilītprogramma javac.exe) jābūt PATH mainīgajā
  • Drukas kļūdas Javas kompilators bieži ziņo kā "nedefinētus mainīgos" vai "neeksistējošas metodes"
  • Faila nosaukumam burtiski jāsakrīt ar tajā definētās klases nosaukumu (būtisks arī lielo/mazo burtu lietojums faila vārdā - ievērojiet, ka DOS failu sistēmā failu vārdi nav reģistrjūtīgi, bet URL adreses IR reģistrjūtīgas)

Izpildes laika kļūdas

Arī izsaucot interpretatoru java var rasties kļūdas, ko sauc par izpildes laika kļūdām (runtime errors). Piemēram,

  • Can't find class ClockMain
  • Exception in thread "main" java.lang.NoSuchMethodError: main

Šādas kļūdas varētu rasties, ja klasei ClockMain nevar atrast sakompilētu CLASS failu (t.i. tas neatrodas nevienā no CLASSPATH norādītajām direktorijām vai JAR failiem. Otrajā gadījumā - ja klasē ClockMain nav definēta metode "main" ar pareizu prototipu, t.i.:

public static void main(String[] args)

Sk. attēlu: Izpildes laika vide (runtime environment)

Aplikāciju kompilācija un izpilde

Jautājumi paškontrolei

  • Raksturojiet Javas tehnoloģijas pamatīpašības
  • Definējiet terminus klase un aplikācija
  • Uzrakstiet, kompilējiet un palaidiet vienkāršu Javas aplikāciju
  • Aprakstiet JVM funkcijas
  • Aprakstiet, kā darbojas drazu savākšana
  • Uzskaitiet trīs darbības Javas platformā, kuras garantē koda drošību

Diskusiju tēmas

  • Faili .class, kuri rodas Javas kompilēšanas rezultātā atbilst atklātam standartam, kurš ir realizēts visās standartiem atbilstošās Javas Virtuālajās Mašīnās (JVM). Kādas ir iespējas no .class failiem reģenerēt Javas izejas kodu (.java failus)? Citiem vārdiem, pārdomājiet "reverse engineering" uzdevumu. Kādas ir sekas, ja Javas izstrādātāji vēlas noslēpt savu programmu izejas tekstus gatavā produktā?
  • Javas programmām parasti ir vajadzīgs Javas interpretators, lai tās varētu palaist. Vai ir iespējams (un vai ir lietderīgi) Javas aplikāciju pārveidot par izpildāmu EXE, lai to būtu vieglāk izplatīt uz datoriem, uz kuriem nav Javas interpretatora.
  • Kādi ir rīki, lai darbinātu Javu ar JIT (Just in time), tādējādi panākot lielāku ātrdarbību?