Appleturi Java (I)


Articolul de fata face parte dintr-un set de articole care se adreseaza atat celor familiarizati cu programarea orientata pe obiecte cat si celor care nu cunosc limbaje OO. Voi aminti pe scurt in
1.1. caracteristicile unui limbaj orientat pe obiecte. Pentru mai multe detalii despre obiecte, recititi articolele despre Java aparute in numerele trecute ale revistei noastre. In 1.2. voi prezenta caracteristicile programarii orientate pe obiecte in Java si apoi vom trece la construirea de exemple (un prim exemplu este 1.3.). Astfel veti invata din exemple.
Daca o anumita notiune nu este clara la un moment dat, nu-i nimic, vom reveni asupra ei. Totul se va clarifica folosind exemplele.
Exemplele prezentate pot fi compilate folosind Java Development Kit (JDK) care poate fi obtinut free de la adresa
www.sun.com, Microsoft Vijual J++ sau orice alt mediu de dezvoltare Java.

1.1. Introducere. Programarea orientata pe obiecte

Programarea orientata pe obiecte este procesul de construire a aplicatiilor cu obiecte. Pentru a intelege cum lucreaza un limbaj orientat pe obiecte, iata cateva notiuni de baza:
O clasa defineste un tip abstract de date. Ea are o definitie al carei format simplificat este:

class nume {lista_elementelor_membru}
Lista_elementelor_membru
cuprinde date membru si functii membru (metode).
Un obiect este o data de un tip definit printr-o clasa. Se spune ca un obiect este o instantiere a clasei respective.
Un limbaj orientat pe obiecte are urmatoarele caracteristici: incapsularea, mostenirea si polimorfismul.
Incapsularea
este un mecanism care leaga impreuna functii si date si le pastreaza in siguranta fata de interventii din afara si de utilizari gresite. Asadar un obiect este o entitate logica ce incapsuleaza atat date cat si functii care manevreaza aceste date.
Mostenirea
este procesul prin care un obiect poate sa preia prototipul altui obiect. Acest lucru introduce conceptul de clasificare. De exemplu, un trandafir face parte din clasa floare care face parte din clasa plante etc. Mecanismul mostenirii este acela care face posibil ca un obiect sa fie un exemplar specific al unui caz mai general. Clasa initiala se numeste clasa de baza, clasa parinte sau superclasa si clasa care deriva din clasa de baza se numeste clasa derivata, clasa copil sau subclasa.
Polimorfismul
. Uneori o metoda a clasei parinte nu se potriveste si clasei copil. Atunci functia va fi suprascrisa in clasa derivata. Alteori aceeasi functie trebuie sa execute altceva in functie de situatie. Acest proces se numeste polimorfism.

1.2. Programarea orientata pe obiecte in Java

Limbajul Java a fost construit de firma Sun pornind de la limbajul C++, dar au fost indepartate unele aspecte din C++, precum supraincarcarea operatorilor si mostenirea multipla. De asemenea, pointerii lipsesc complet din limbajul Java, eliminandu-se astfel una din principalele surse de erori. In plus, eliberarea memoriei ocupate de obiecte si masive se face automat, printr-un "mecanism de colectare de gunoaie". Limbajul Java mai are inclus un suport pentru aplicatii care lucreaza cu mai multe fire de executie, inclusiv primitive de sincronizare intre firele de executie (vom vedea acest lucru mai tarziu).
Limbajul Java lucreaza folosind setul de caractere Unicode. Acesta este un standard international al carui set de caractere este reprezentat pe 16 biti. Vechiul standard ASCII este un subset al standardului Unicode, adica vom regasi aici caracterele ASCII cu exact aceleasi coduri. Diferenta majora este ca o variabila Java de tip caracter, de exemplu, este reprezentata pe 16 biti, iar un sir de caractere va ocupa de doua ori mai multa memorie decat numarul caracterelor. Analog, o variabila de tip intreg, care in C era reprezentata pe 16 biti, acum va fi reprezentata pe 32 de biti. Avantajul setului Unicode este ca, fiind reprezentat pe 16 biti, are posibilitati mult mai mari.
Spre deosebire de alte limbaje orientate pe obiecte (de ex. C++), in Java fiecare linie de cod apartine unei clase. Alfel spus, un program sursa Java este format numai din clase si interfete (veti vedea in curand ce inseamna toate acestea).
Pentru ca un program scris in Java sa devina functionabil, trebuie sa fie mai intai compilat si apoi interpretat. Un program sursa are extensia .
java. Numele sau trebuie sa fie identic cu numele clasei sau interfetei publice declarate in interiorul sursei. In urma compilarii rezulta fisiere cu nume identice cu numele claselor, dar cu extensia .class, indiferent daca este vorba de o clasa sau o interfata (vor fi create atatea fisiere .class cate clase si interfete sunt definite in fisierul sursa).
Odata fisierele compilate, acestea pot rula ca aplicatii sau apleturi. O aplicatie este un program care va fi rulat de sine-statator, cu ajutorul unui interpretor (java sau jview). Un aplet Java ruleaza intr-un document HTML si fisierele compilate .
class sunt interpretate de Java Virtual Machine. Acesta este un software care sta pe masina unde fisierele compilate .class vor fi rulate (JVM este instalat odata cu instalarea browserului de web).
Scopul acestui set de articole este crearea de apleturi Java (de cele mai multe ori codul pentru apleturi difera intr-o oarecare masura de codul pentru aplicatii).

Sintaxa folosita pentru a crea o noua clasa in Java este:

modificator class numeclasa [extends clasaparinte] [implements interfete]
modificator
poate fi unul din urmatoarele cuvinte cheie:
public
– o clasa declarata public poate fi folosita de orice obiect. De retinut ca un fisier sursa .java poate avea o singura clasa publica. Numele fisierului sursa trebuie sa fie identic cu numele clasei publice;
private
– o clasa declarata private poate fi folosita numai de clase din acelasi fisier sursa. O sursa .java poate contine numai o clasa publica, dar mai multe clase private;
<nimic>
- daca nu este specificat nici un modificator, clasa va fi considerata "friendly" (prietenoasa) (a nu se confunda cu clasele sau functiile friend din C++!), ceea ce inseamna ca toate celelalte clase din acelasi pachet (veti vedea mai jos ce este un pachet) pot accesa clasa respectiva;
synchronizable
– este folosit pentru a sincroniza elementele (vom vedea mai tarziu);
abstract
– o clasa abstracta contine numai metode fara implementare (corpul functiei nu este definit aici) si este folosita drept clasa de baza pentru eventuale clase care deriva din ea;
final –
o clasa finala nu poate fi mostenita (alte clase pot accesa clasa finala, dar nici o alta clasa nu poate deriva din ea).
Urmatorul exemplu arata o clasa publica si una privata care pot fi create in acelasi fisier sursa:

Public class clasa1 {
    int x;
    MetodaX(int x);
}
private class clasa2 {
    int y;
    MetodaY(int y);
}

Asa cum clasele pot fi declarate folosind modificatorii descrisi mai sus, Java permite si ca variabilele si metodele sa fie prefixate de unul din urmatorii modificatori:

public
– o metoda sau variabila declarata public poate fi accesata de orice clasa;
protected
– poate fi accesata numai de subclase;
private
– poate fi accesata numai de metode din aceeasi clasa;
<nimic>
- daca nu este specificat nici un modificator, metoda sau variabila poate fi accesata de orice alta clasa din acelasi pachet;
static
– specifica o metoda sau variabila valabila global pentru toate instantele unei clase;
native
– denota o metoda implementata in alt limbaj de programare (de ex. C++)
final
– specifica o variabila constanta (valoarea ei nu poate fi schimbata in momentul rularii) sau o metoda care nu poate fi supraincarcata de o clasa derivata.
synchronized
– acest cuvant cheie blocheaza obiectul atunci cand aceasta metoda este apelata si il deblocheaza atunci cand se iese din metoda.

In Java mostenirea se realizeaza prin folosirea cuvantului cheie
extends. Astfel, clasa derivata va "mosteni" toate variabilele si metodele definite in clasa de baza si va adauga variabile si metode specifice (veti vedea putin mai jos un exemplu).
Spre deosebire de limbajul C++, in Java o clasa poate mosteni numai o singura clasa. Java permite extinderea acestei functionalitati prin intermediul interfetelor.
O interfata este o declaratie a unui set de metode care nu sunt implementate. O clasa implemeteaza o interfata prin cuvantul cheie
implements si este responsabila pentru scrierea codului metodelor definite in interfata. O interfata poate deriva din una sau mai multe interfete. Desi o clasa poate mosteni o singura clasa, ea poate implementa oricate interfete.
Exemplu de derivare a unei clase folosind mostenirea si implementarea:
Sa presupunem clasa de baza
om si interfata comportament, definite astfel:
public class om {
   int anul_nasterii;
   char sex;
   int returneaza_varsta(int anul_nasterii) {
      cod…
   };
}

public interface comportament {
   void citeste();
   void mananca();
   void danseaza();
}

Sa derivam clasa
student din clasa om si sa implementam interfata comportament:
public class student extends om implements comportament{
   String facultatea;
   int anul;
   int note[20];
   int calculeaza_media(int note[]){cod…};
   void citeste(){
      corpul_functiei_citeste;
   }
   void mananca(){
      corpul_functiei_mananca;
   }
   void danseaza();{
      corpul_functiei_danseaza;
   }
}


Mai multe clase si interfete care au ceva in comun pot fi grupate intr-un pachet (package) adaugand urmatoarea linie la inceputul fiecarui fisier sursa:

package nume_pachet;

Sa presupunem ca am creat clase si interfete care reprezinta persoane:

class om;
class student;
interface comportament;
class profesor;
class muncitor;

Putem grupa aceste clase si interfete intr-un pachet numit persoana scriind linia
package persoana la inceputul fiecarui fisier sursa care contine clasele de mai sus.

Realizatorii limbajului Java au creat si un numar mare de pachete (dintre care enumar: java.applet, java.awt, java.io, java.lang, java.math, java.net, java.security, java.sql, java.text, java.util). Fiecare contine clase si interfete pentru a fi reutilizate de programator. Daca aveti JDK, in directorul unde l-ati instalat se afla un fisier \lib\classes.zip. Daca ati instalat Vijual J++, in directorul c:\windows\java\classes\java\ veti gasi mai multe directoare. Daca nu ati instalat inca un mediu de dezvoltare Java, dar aveti un browser cu capacitati Java, de exemplu Internet Explorer pe un mediu Windows 95/98, uitati-va prin fisierele .zip din directorul c:\windows\java\packages\. Exista o conventie conform careia numele pachetelor au fost create pe structura directoarelor. Astfel, pentru a crea subpachetul cu numele
java.applet, a fost creat un director cu numele java, apoi un subdirector al acestuia cu numele applet. Toate subpachetele lui applet se vor afla in directorul applet. Va recomand ca pe masura ce invatati sa programati in Java, sa va uitati prin fisierele acestor directoare pentru a intelege structura ierarhica a claselor si functiile si variabilele definite de fiecare clasa.
Asadar, iata, pe scurt, cate ceva despre cateva dintre aceste pachete:

  1. Pachetul java.applet contine clase folosite pentru a crea apleturi Java si pentru a lucra cu ele. Fiecare aplet este derivat direct din clasa java.applet.Applet din acest pachet.
  2. Pachetul java.awt contine clasele si subpachetele care alcatuiesc Java Abstract Windowing Toolkit (AWT). Acest pachet furnizeaza principalele clase care permit unei aplicatii GUI (Graphical User Interface) scrise in Java sa ruleze pe orice platforma. Cateva exemple de clase incluse in pachetul java.awt sunt: Button, List, Menu, CheckBox, Color, Font, Graphics, Image, Point, Rectangle, Polygon, Window etc.
  3. Pachetul java.io contine clase cu capacitati de intrare/iesire. Programatorul poate citi de la intrarea standard sau scrie la iesirea standard: File, FileInputStream, FileOutputStream, DataInputStream etc.
  4. Pachetul java.lang contine clasele care corespund tipurilor de date de baza (Integer, Boolean, Float, Character, Long, Double). In acelasi pachet sunt incluse si clasele System ( furnizeaza informatii ale sistemului unde ruleaza) si Thread (furnizeaza posibilitatea crearii mai multor fire de executie);
  5. Pachetul java.net include clase pentru comunicatii intre procese pe masini diferite (dintr-o retea de calculatoare). Clasele URL, URLConnection, Socket, InetAddress sunt cateva exemple.
  6. Pachetul java.util ofera un mare numar de clase utile ca: Date, Dictionary, Hashtable, Stack, Vector etc.

Clasele cuprinse in aceste pachete si functionalitatile lor vor fi explicate pe masura ce voi prezenta exemple. Fiecare exemplu va folosi clase din aceste pachete.

1.3. Exemplul 1
In primul exemplu vom invata sa scriem un text, sa desenam diferite forme geometrice etc.

Clasele din pachetele despre care tocmai am vorbit sunt folosite intr-un program prin includerea la inceput a unei linii de forma: import numeClasa;
Clasa java.applet.Applet este clasa de baza din care deriva orice aplet, deci ea trebuie inclusa intotdeauna cand construim un aplet. Pentru a putea folosi elemente grafice, vom mai include clase din pachetul java.awt.

Iata un prim exemplu de aplet:
import java.applet.Applet;

import java.awt.Graphics;

public class PrimulAplet extends Applet{
    public void paint(Graphics g){

        g.drawString("Primul aplet",50,25);

    }

}

Metoda paint este mostenita de clasa Applet (de la clasa Component) si se foloseste pentru a desena obiecte. Ea are antetul public void paint(Graphics g). Aici am suprascris-o (iata deci un exemplu de polimorfism!) pentru a executa ceea ce dorim noi.
Functia care realizeaza afisarea unui text este drawString (functie membra a clasei Graphics), ce primeste ca parametri textul de afisat si coordonatele x si y unde textul respectiv va fi scris pe ecran.

Pentru a vedea rezultatele rularii acestui aplet, trebuie ca fisierul HTML sa contina urmatoarea linie:

<applet code="PrimulAplet.class" width=150 height=25></applet>
Putem introduce in sursa HTML parametrii care vor fi transmisi apletului, astfel:
<applet  ...>

<param name=titlu value="Acesta este primul meu aplet">

</applet>

Atunci modificam codul apletului folosind functia getParameter(String nume), membra a clasei Applet:
public class PrimulAplet extends Applet{
    private String sir;

    public void init(){

        sir=getParameter("titlu");

        if(sir==null) sir="Primul aplet";

    }

    public void paint(Graphics g){

        g.drawString(sir,50,25);

    }

}

Intr-un aplet java nu exista o functie main (cum este in C++ sau in aplicatiile java), care determina apelul celorlalte functii. Atunci care este ordinea in care vor fi executate functiile?
Executia unui aplet este marcata de cateva evenimente importante generate de catre browser. La intalnirea etichetei <applet>, browserul incarca fisierul necesar rularii apletului (fisierele .class). Apletul nu poate rula pana cand codul nu a ajuns pe calculatorul client.

Dupa incarcarea codului, apletul este apelat automat pentru initializare prin functia init(). Este momentul in care apletul isi pregateste parametrii si obtine de la sistem resursele necesare rularii. In exemplul nostru functia init citeste parametrul titlu transmis apletului de fisierul HTML.

Dupa ce initializarea a fost terminata, browserul trimite catre aplet o comanda de pornire (functia start()). Un aplet ruleaza atat timp cat navigatorul este activ. La schimbarea paginii curente, apleturile din vechea pagina primesc o comanda de oprire temporara (functia stop()). La inchiderea browserului este lansata functia destroy() care distruge toate variabilele alocate, eliberand memoria. Toate aceste functii sunt definite in clasa Applet si sunt apelate automat de sistem. Daca sunteti atenti, atunci cand Internet Explorer incarca un aplet java, scrie pe bara de jos mai intai "Applet initialized", apoi "Applet started", care va sta scris atata vreme cat apletul este activ. Daca apasati butonul "Refresh", va scrie "Applet stopped", si apoi va trece iar la initializare (cu init()) si va porni din nou apletul (cu start()).

Orice aplet Java reprezinta deci un nou tip de obiect, derivat din obiectul standard Applet.

Sa desenam acum pe ecran diferite obiecte grafice. Pentru aceasta, sa folosim urmatoarele functii, care au fost definite in clasa java.awt.Graphics astfel:
- public abstract void drawLine(int x1, int y1, int x2, int y2); deseneaza o linie de la punctul (x1,y1) la punctul (x2,y2), cu culoarea curenta (vom vedea cum o putem schimba);

- public void drawRect(int x, int y, int width, int height); deseneaza un patrat cu coltul din stanga sus (x,y) si de latimea width si inaltimea height;

- public abstract void fillRect(int x, int y, int width, int height); deseneaza un patrat plin;

- public abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight); deseneaza un patrat cu colturile rotunde;

- public abstract void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight); deseneaza un patrat plin cu colturile rotunde;

- public void draw3DRect(int x, int y, int width, int height, boolean raised); daca parametrul raised are valoarea true, deseneaza un patrat cu umbra (asa cum sunt butoanele); iar daca este false, deseneaza un patrat ca un buton apasat;

- public void fill3DRect(int x, int y, int width, int height, boolean raised); un patrat plin cu umbra;

- public abstract void drawOval(int x, int y, int width, int height); deseneaza un oval cu parametri specificati (desigur ca daca width si height sunt egale, va fi desenat un cerc);

- public abstract void fillOval(int x, int y, int width, int height); un oval (cerc) plin;

- public abstract void drawPolygon(int xPoints[], int yPoints[], int nPoints); deseneaza un poligon cu nPoints colturi definite de vectorii xPoints si yPoints;

- public abstract void fillPolygon(int xPoints[], int yPoints[], int nPoints); un poligon plin.

Pentru alte functii definite in clasa Graphics, cititi fisierul Graphics.java (din directorul java\awt\).

Putem schimba culoarea curenta cu ajutorul functiei definita tot in clasa Graphics astfel:
public abstract void setColor(Color c);

Pentru aceasta trebuie sa cunoastem mai intai clasa Color, care face parte tot din pachetul java.awt.

Clasa Color defineste constante corespunzatoare culorilor uzuale: white, lightGray, gray, darkGray, black, red, pink, orange, yellow, green, magenta, cyan si blue. Astfel, de exemplu, pentru a seta culoarea curenta pe rosu vom scrie linia g.setColor(Color.red), unde g este un obiect de tipul Graphics. Putem seta culoarea curenta pe o culoare care nu a fost definita ca o constanta apeland unul dintre constructori (vezi fisierul Color.java), ca exemplu: Color c = new Color(123,200,255).

Culoarea de background a apletului se seteaza cu ajutorul functiei setBackground(Color c), mostenita de clasa Applet. Acesta linie trebuie scrisa in corpul metodei init() pentru ca apletul trebuie sa stie inca de la initializare care este culoarea de background (nu poate fi schimbata dupa aceea);

Acum aveti destule cunostinte pentru a putea desena cu orice culoare obiecte grafice pe ecran. Va recomand sa construiti apleturi folosind functiile prezentate si eventual si alte functii definite in clasele Graphics si Color. Iata un exemplu! Aici puteti vedea apletul ruland.

import java.awt.*;
import java.applet.Applet;

public class Desene extends Applet {

 private String mesaj;

 public void init() {
     mesaj = getParameter("titlu");

     if(mesaj==null) mesaj="Uite ce-am invatat sa desenez in Java! :)) :";

     setBackground(Color.cyan);

 }

 public void paint(Graphics g) {
     g.setColor(Color.black);

     g.drawString(mesaj,10,15);

     g.setColor(Color.blue);

     g.drawLine(10,50,30,100);

     g.drawRect(50,50,50,50);

     g.setColor(Color.red);

     g.fillRoundRect(120,50,50,50,20,20);

     g.setColor(Color.magenta);

     g.fill3DRect(190,50,50,50,true);

     g.setColor(Color.pink);

     int xpoli[]={250,300,320,380,320,250,250};

     int ypoli[]={50,50,80,80,120,100,50};

     g.fillPolygon(xpoli,ypoli,7);

     Color c = new Color(100,20,200);

     g.setColor(c);

     g.drawOval(400,50,50,50);

 }

}

 


 

1