Jump to content
Grunt

Primii pasi in Java

Recommended Posts

ATENTIE: Tutorialul nu este complet. Il voi completa pe masura ce am timp.

INTRODUCERE

Multa lume face tutoriale in ultimul timp. Pentru Pascal, pentru QBasic, limbaje arhaice, care lucreaza pe principiul programarii iterative. Practic, se ia fiecare instructiune si se executa. Programul este doar o inlantuire de instructiuni, ca o versiune putin mai avansata a assembler-ului. Ei bine, exista si alte paradigme de programare, si aici incepem cu programarea orientata-obiect. In cazul de fata, programul nu mai e o inlantuire de instructiuni, ci o suita de obiecte ("bucati" ce au o stare proprie, si zona proprie de memorie) ce interactioneaza intre ele.

ISTORIA JAVA, ALTE ASPECTE GENERALE

Limbajul Java este relativ nou, aparut in anul 1995 si dezvoltat de firma Sun. Este gratuit, si, din 2006 cred, open-source. A aparut din dorinta unora de a face un limbaj extrem de usor de utilizat.

Este bazat pe sintaxa C++, deci trecerea de la C->C++->Java pare fireasca. Java aduce totusi cateva lucruri noi. Unele cuvinte-cheie (transient, volatile etc), masina virtuala Java, programul pur orientat-obiect (spre deosebire de C++, care e un limbaj hibrid).

Pentru a putea rula programe Java aveti nevoie de Java Runtime Environment (masina virtuala de la Sun), sau orice alta masina virtuala Java (exista si OpenJRE, si altele). Pentru a putea compila programe Java aveti nevoie de un Java Development Kit (JDK). RECOMAND CU TARIE si un IDE pentru Java, pentru ca JDK-ul vine cu o imensitate de clase gata de folosit, iar un IDE precum NetBeans va ajuta foarte mult sa profitati de ele, nefiind nevoie sa scrieti cod pentru lucruri care deja exista. De asemenea, va ajuta sa proiectati intefete grafice.

Java este un limbaj compilat si interpretat. Codul sursa initial este tradus intr-un limbaj binar (bytecode) asemanator instructiunilor elementare ale procesorului. Asa cum un procesor executa aceste intructiuni, la fel masina virtuala Java executa (mai bine zis interpreteaza si executa) acel bytecode din fisierele .class. Ca dezavantaj, avem performanta mai scazuta decat in cazul executabilelor clasice compilate, de ex., cu C. Ca avantaje, avem: securitatea sporita (programul nu mai are acces direct la sistem, nu poate cauza un system crash etc), si portabilitatea pe toate platformele pentru care exista o masina virtuala Java.

Regula: odata compilat cu succes, programul va rula cu succes pana cand:

1. Masina virtuala nu mai are destul memorie (destul de rar, pentru ca Java are un garbage collector automat, care curata memoria de fiecare data cand e nevoie, in sensul ca dealoca obiectele nefolosite)

2. Apare o exceptie care se propaga pana la masina virtuala (despre asta voi explica pe larg mai tarziu).

HELLO WORLD, IN JAVA

Odata ce aveti un editor text si JDK-ul instalat, puteti crea programe Java. Cel mai simplu program este urmatorul:

public class HelloWorld {
public static void main(String argv[]) {
System.out.println("Hello world!");
}
}

Lucruri pe care trebuie sa le observati:

1. main() se afla intr-o clasa (Java este pur orientat-obiect!)

2. parametrul lui main() este mereu un vector de String (String[])

Odata scris codul, salvati-l intr-un fisier cu numele HelloWorld.java. ATENTIE: Numele fisierului trebuie sa fie la fel cu al clasei ce contine functia main(). Compilatorul Java poate fi invocat din linie de comanda (javac HelloWorld.java), rezultand fisierul HelloWorld.class. Rularea lui se face cu java HelloWorld. Atentie din nou: la rulare, nu dati un nume de fisier, ci un nume de clasa! Folosind un IDE, nu mai aveti nevoie de linie de comanda, compilarea si rularea sunt la un click distanta.

TIPURI DE DATE

Exista doua tipuri de date in Java. Tipuri primitive, si clase. Tipurile primitive sunt cele cunoscute deja de programatorii C/C++: int, short, long etc. Avem insa doua diferente majore: exista noul tip boolean (neexistent in C, bool in C++), iar sizeof(char)=2, si nu 1. Va intrebati, de ce 2 octeti pentru un caracter? Pentru ca Java foloseste setul Unicode, de unde si usurita internationalizarii programelor.

Clasele sunt principalele entitati ale programarii orientate-obiect. Pentru simplitate, o clasa este pentru un obiect ce este un tip pentru o variabila, adica generalizarea obiectului. In C++, nu exista nici o diferenta semantica intre o structura (struct) si o clasa (class), iar Java nu schimba cu nimic asta. Cum spunem de ex. "i este de tip int", asa putem spune "oraCurenta este o instanta a clasei Hour".

O clasa poate contine: date membre, si operatii ce pot fi facute cu acestea (metode). Sa zicem ca avem:

class Numar {
int nr;
Numar() { this.nr = 0; }
Numar(int nr) { this.nr = nr; }
void add(int x) { nr += x; }
}

Am definit cu succes o clasa cu numele Numar, care are un membru x, si o metoda cu numele add, ce aduna la numarul membru un alt intreg. Putem defini obiecte de tip Numar, putem sa le dam valori, putem sa facem adunari. Inainte de asta, insa... Fiecare clasa are un constructor. Asa cum sugereaza numele, el construieste obiectul. Mai sus, constructorul e metoda care are acelasi nume cu cel al clasei. O clasa poate avea mai multi constructori, cu conditia ca ei sa aiba parametri de tipuri diferite. Constructorul nostru primeste ca parametru un numar, si da valoarea lui membrului nostru. In caz ca un parametru intr-o metoda are acelasi nume ca o data membru, puteti folosi this (cum vedeti in exemplu) pentru a va referi la membrul obiectului curent.

Acum, hai sa facem cateva operatii cu obiecte:

1. Numar n = new Numar(3);
2. Numar m = new Numar();
3. int a = 3;
4. n.add(a);
5. m.add(a);

La linia 1 creem un obiect "n", care este o instanta a clasei Numar. Parametrul pe care il vedeti arata ca se apeleaza constructorul nostru, deci n.x o sa fie 3. La linia 2 instantiem un alt obiect. Este apelat constructorul fara parametri (cel implicit), si m.x o sa fie 0. La liniile 4 si 5 facem operatiile de adunare, dupa care n.x o sa fie 6, iar m.x o sa fie 3.

Class dismissed. O sa mai continui cand o sa am timp/chef.

Link to comment
Share on other sites

PACHETE

Majoritatea limbajelor de programare permit includerea altor fisiere (gen: #include <iostream> in C++, sau uses dos; in Pascal). Java detine o tehnica similara, insa in acest limbaj nu includem fisiere, ci clase. Pentru o buna organizare, clasele sunt organizate in pachete. Atunci cand cream o clasa, putem sa ii dam un nume de pachet, iar, dupa compilare, fisierul .class va fi pus intr-un folder cu numele pachetului. De exemplu:

package my.new.package;
public class MyClass { ... }

Numele complet al clasei este my.new.package.MyClass. Ca sa nu scriem atat de mult (am putea sa folosim clasa destul de des in cod), putem sa adaugam import my.new.package.MyClass; inainte de a o folosi (preferabil la inceputul fisierului sursa), si gata. Clasa este importata.

Java contine numeroase clase, suficiente pentru oricine: lucru cu fisiere, lucru in retea, unelte pentru parsare/procesare XML, si multe, multe altele. Dar, sa incepem cu ceva simplu. Pentru a putea redenumi un fisier, trebuie sa folosim clasa File, care se gaseste in pachetul java.io. (NOTA: Pentru cei care folosesc Netbeans, versiunile de la 6 in sus permit adaugarea automata a import-urilor dupa numele claselor. Ceilalti trebuie sa adauge import-urile manual).

import java.io.*;
class Ceva { Ceva() { File f = new File("asd.txt"). f.rename("asd2.txt"). f.close(); }

Putem sa importam si mai multe clase odata (java.io.*), dar nu toate vor fi importate, ci numai cele folosite explicit in cod.

TRATAREA ERORILOR. EXCEPTII

Dupa cum am mai precizat, Java foloseste exceptii pentru tratarea cazurilor exceptionale. Asta datorita faptului ca se poate scrie cod mult mai usor de inteles. Sa luam doua exemple, care incearca sa imparta doua numere, deimpartitul trebuind sa fie pozitiv:


try {
if (a<=0) throw new ArithmeticException("Deimpartitul e negativ!");
if (b==0) throw new ArithmeticException("Impartitorul nu poate fi 0!");
// calcule intensive si nefolositoare urmeaza
}
catch (ArithmeticException e) { System.out.println(e.getMessage()); }
catch (Exception e) { System.out.println("Some other exception occured"); }

Acest tip de tratare a erorilor separa in mod eficient zona algoritmului nostru, de zona de tratare a erorilor. In mod obisnuit, cu o inlantuire de if-uri si verificare a codurilor returnate de functii, se poate ajunge la un iad al debug-ului.

IERARHIA DE CLASE

Dupa cum am mai mentionat, Java, ca un limbaj orientat-obiect, suporta mostenire. Hai sa elaboram acest concept.

Sa zicem ca, in cod, avem definita clasa Persoana, ce contine: nume, prenume, varsta. Undeva in viitorul indepartat, o sa folosesc majoritatea codului scris de mine ca sa fac un catalog al unei clase (de elevi!). Nu vreau sa rescriu tot codul, si copy/paste ma omoara cu draci ca nu imi merge tasta CTRL. Ce sa ma fac... Simplu! Din clasa Persoana, cream o clasa noua, care sa o mosteneasca, si care sa contina aceleasi metode si aceiasi membri, si sa pot adauga lucruri noi:

class Elev extends Persoana {
unsigned nota_istorie[], nota_romana[];
/// etc, etc, etc
}

Am creat clasa Elev, care contine aceiasi membri ca si Persoana (nume, prenume, varsta), dar si niste vectori cu notele sale la anumite discipline. La fel, putem crea clasa Profesor din Persoana, care sa contina si numele disciplinei pe care o preda.

In acest fel se pot crea inlantuiri de clase, pe baza mostenirii. De exemplu: Persoana <- Student <- StudentInformatica <- Grunt. Sagetile indica directia mostenirii. Si nu doar o inlantuire, ci un intreg arbore de clase. Java, cu toate clasele sale din libraria standard, are un asemenea arbore, unde radacina este clasa Object. Asadar, orice obiect creat in Java va fi mostenitor al clasei Object. Fara exceptii. Un File este un Object, o Persoana este un Object.

FUNCTII VIRTUALE. POLIMORFISM

Probabil unul dintre cele mai importante mini-capitole ale acestui tutorial. Polimorfismul este baza programarii orientate-obiect.

DEFINITIE: Polimorfismul este un paradigm al programarii, in care semantica apelului unei functii nu apartine apelantului, ci apelatului. Hai sa elaboram. In C, am putea scrie: "int x = numarulElevilor("12A")", ca sa aflam numarul elevilor din clasa 12A, ceea ce este foarte corect si clar. Dar, daca fiecare clasa (de elevi!) ar sti sa isi returneze numarul de elevi intr-un mod UNITAR? Aici intervin functiile virtuale.

EDIT: Da, Vhaerun are dreptate, in Java toate functiile sunt implicit virtuale. Imi pare rau de confuzie.


class Dreptunghi {
double lung, lat;
double arie() { return lung * lat; }
}

class Patrat extends Dreptunghi {
double arie() { return lung*lung; } // patratul nu are latime
}

Urmatoarea instructiune ar parea ciudata, cel putin: "Dreptunghi x = new Patrat()", dar e perfect legala, pentru ca un Patrat este tot un Dreptunghi, insa unul mai special. Am declarat un Dreptunghi (corect), si am initializat un patrat (la fel corect), apoi am dat dreptunghiului valoarea patratului (foarte corect). Iata minunatia mostenirii. In acest fel, putem sa tratam toate Patratele ca fiind Dreptunghiuri. Spre exemplu, putem aveam un vector de Dreptunghiuri care sa contina si Patrate (Vector<Drepunghi>), ceea ce e, sintactic si semantic, foarte corect.

Insa apare intrebarea: avand un vector de dreptunghiuri, calculand aria unuia dintre ele nu ar fi gresita, dat fiind ca acel dreptunghi ar putea fi un patrat? Raspuns: NU. Sa luam codul urmator:

Vector<Dreptunghi> d = new Vector<Dreptunghi>();
d.add(new Dreptunghi(2,3));
d.add(new Patrat(2));
System.out.println(d.get(0).arie());
System.out.println(d.get(1).arie());

Afisand ariile elementelor din vector, vedem ca ele sunt calculate corect, fara sa conteze daca sunt Dreptunghiuri sau Patrate. Cum se poate? Asta e polimorfismul. Putem trata unele obiecte ca alte obiecte. d.get(1), care este un Patrat, noi il vedem ca un Dreptunghi, dar, dat fiind ca ele au functii diferite de calcul al ariei, vom avea rezultatul corect de fiecare data, chiar daca au acelasi nume. Frumos, nu?

CLASE ABSTRACTE. INTERFETE.

Sa generalizam exemplul Dreptunghiului, si sa ne gandim la o Figura, cu metoda arie(). Dar... fiind o Figura, nu stim in ce fel sa calculam aria! Triunghiurile au o formula, Patratele alta formula... Ce ne facem? Ideal ar fi sa lasam functia neimplementata in clasa de baza (Figura), si, in fiecare clasa mostenitoare, sa le implementam. In acest caz, avem nevoie de o clasa abstracta, sau o interfata.

abstract class Figura {
double arie() { return 0; }
}

Am creat o clasa abstracta, care contine functia arie(), si care va trebui reimplementata in fiecare clasa mostenitoare. Clasa Figura nu poate fi instantiata, dar poate fi mostenita. La fel pot fi definite functii abstracte, fara implementare. Orice clasa care nu implementeaza functiile din clasa abstracta trebuie sa fie tot abstracta.

interface Figura {
virtual double arie();
}

O interfata reprezinta un set de "reguli" la care adera o clasa. Este un principiu Java pentru a implementa mostenirea multipla oferita de C++, insa intr-un alt mod. O clasa poate sa mosteneasca o singura clasa, dar poate implementa oricate interfete. Pentru a o folosi in clasa noastra procedam in felul urmator:

class Patrat implements Figura {
virtual double arie() { return l*l; }
}

Acum stiti destule pentru a scrie programele voastre. Mult noroc.

Nu sunt sigur ca o sa continui tutorialul. De acum, trebuie sa va familiarizati cu libraria standard Java (pachetele java.lang, java.io java.net, javax.swing etc), pentru care se gasesc destule tutoriale/exemple pe Internet.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...