Sunteți pe pagina 1din 35

Tehnici Avansate de Programare

Indrumar Laborator
Nota laborator = Activitate laborator sau/si Examen Activitate laborator: in fiecare ora de laborator este propusa cate o problema. Rezolvarea acesteia in timpul laboratorului duce la obtinerea unui punct (1p). Daca din activitatea de laborator se obtin cel putin 6 puncte nu mai este necesara prezentarea la examen. In acest caz, Nota laborator = Activitate laborator. Examenul consta din rezolvarea (la calculator) a unei probleme asemanatoare cu cele propuse in timpul semestrului. Pentru studentii care nu au Activitate de laborator, Nota laborator = Examen. Pentru studentii care au atat Activitate de laborator cat si nota la examen, nota finala se calculeaza astfel: Nota laborator = Examen + Activitate / 4. Pentru promovarea laboratorului este necesara obtinerea unei note mai mari sau egala cu 5. Situatia la laborator este disponibila la adresa http://www.adrianroman.ro/upm/tap/note.xls

Laborator 1
- Instalare Java: 1. 2. 3. 4. 5. Navigare http://java.sun.com/ si apoi se apasa meniul Downloads Din Java SE se selecteaza Java SE(JDK) Se apasa butonul de Download de langa JDK 6 Update 3. Din pagina se selecteaza oricare din cele 2 optiuni de download. Se urmeaza intructiunile de instalare.

Link-ul direct de download este: https://sdlc5d.sun.com/ECom/EComActionServlet;jsessionid=67A900B217B5F98456E0E 3B40D96CD27 - Rulare primul program Java (https://java.sun.com/docs/books/tutorial/getStarted/cupojava/win32.html): 1. Se deschide un Notepad (Start -> Run -> notepad [Enter]) si se scrie primul program in Java:
class HelloWorld { public static void main(String args[]) { System.out.println(Hello World!); } }

2. Se salveaza fisierul HelloWorld.java intr-un director (de exemplu D:\Student). 3. Se deschide un Windows Explorer / Total Commander si se cauta calea catre java.exe si javac.exe. De obicei calea este: C:\Program Files\Java\jdk1.6.0_03\bin. 4. Se copiaza calea in Clipboard (Ctrl+C). 5. Se deschide o linie de comanda: Start -> Run -> cmd [Enter] 6. Se executa comanda: path %PATH%; C:\Program Files\Java\jdk1.6.0_03\bin. Pentru accesarea caii din Clipboard se da click dreapta si, din meniu, se selecteaza Paste.

7. Pentru verificare se executa javac, iar rezultatul trebuie sa fie similar cu cel din figura de mai jos:

8. Se navigheaza catre directorul in care se gaseste fisierul HelloWorld.java:


>d: >cd Student

9. Se compileaza HelloWorld.java:
>javac HelloWorld.java

Daca in urma compilarii nu apar erori atunci rezulta fisierul HelloWorld.class. Daca apar erori, acestea trebuie corectate in fisierul HelloWorld.java si apoi trebuie executata din nou comanda de mai sus. 10. Se executa programul Java:
>java HelloWorld

11. Pentru modificarea programului trebuie editat codul aflat in fisierul HelloWorld.java si repetati pasii 9 si 10.

Laborator 2 Pachete in Java (Packages)


Un pachet este o colectie de clase si interfete inrudite din punctul de vedere al functionalitatii lor. Sunt folosite pentru gasirea si utilizarea mai usoara a claselor, pentru a evita conflictele de nume si pentru a controla accesul la anumite clase. In alte limbaje de programare pachetele se mai numesc librarii sau bibilioteci.

Pachetele standard (J2SDK)


Platforma standard de lucru Java se bazeaza pe o serie de pachete cu ajutorul carora se pot construi intr-o maniera simplificata aplicatiile. Exista un set de clase deja implementate care modeleaza structuri de date, algoritmi sau diverse notiuni esentiale in dezvoltarea unui program. Cele mai importante pachete si suportul oferit de lor sunt: java.lang - clasele de baza ale limbajului Java java.io - intrari/iesiri, lucrul cu fisiere java.util - clase si interfete utile java.applet - dezvoltarea de appleturi java.awt - interfata grafica cu utilizatorul java.awt.event - mecanismele de tratare e evenimentelor generate de utilizator java.beans - scrierea de componente reutilizabile java.net - programare de retea java.sql - lucrul cu baze de date java.rmi - executie la distanta Remote Message Interface java.security - mecanisme de securitate: criptare, autentificare java.math - operatii matematice cu numere mari java.text - lucrul cu texte, date si numere independent de limba javax.swing - interfata grafica cu utilizatorul, mult imbogatita fata de AWT.

Folosirea membrilor unui pachet


Conform specificatiilor de acces ale unei clase si ale mebrilor ei, doar clasele publice si membrii declarati publici ai unei clase sunt accesibili in afara pachetului in care se gasesc. Pentru a folosi o clasa publica dintr-un anumit pachet, sau pentru a apela o metoda publica a unei clase publice a unui pachet, exista trei solutii: specificarea numelui complet al clasei importul clasei respective importul intregului pachet in care se gaseste clasa. Specificarea numelui complet al clasei se face prin prefixarea numelui scurt

al clasei cu numele pachetului din care face parte: numePachet.NumeClasa. Button - numele scurt al clasei java.awt - pachetul din care face parte java.awt.Button - numele complet al clasei Importul unei clase sau interfete se face prin instructiunea import in care specificam numele complet al clasei sau interfetei pe care dorim sa o folosim dintr-un anumit pachet: import numePachet.numeClasa; import java.awt.Button; Importul la cerere dintr-un anumit pachet se face printr-o instructiune import in care specificam numele pachetului ale carui clase si interfete dorim sa le folosim, urmat de simbolul *. Se numeste import la cerere deoarece incarcarea claselor se face dinamic, in momentul apelarii lor. import numePachet.*; import java.awt.*;

Crearea unui pachet


Crearea unui pachet se realizeaza prin scrierea la inceputul fisierelor sursa ce contin clasele si interfetele pe care dorim sa le grupam intr-un pachet a instructiunii: package numePachet; Instructiunea package actioneaza asupra intregului fisier sursa la inceputul caruia apare. Cu alte cuvinte nu putem specifica faptul ca anumite clase dintr-un fisier sursa apartin unui pachet, iar altele altui pachet. Daca nu este specificat un anumit pachet, clasele unui fisier sursa vor face parte din pachetul implicit (care nu are nici un nume). In general, pachetul implicit este format din toate clasele si intefetele directorului curent de lucru. Este recomandat insa ca toate clasele si intefetele sa fie plasate in pachete, pachetul implicit fiind folosit doar pentru aplicatii mici sau prototipuri.

Exemplu
1. Se creaza un pachet care sa contina clasa NumerePrime: a. Se creaza directorul Pachet (directorul care contine toate fisierele/clasele din pachetul Pachet ) b. In directorul Pachet se creaza fisierul NumerePrime.java care contine urmatorul cod:
package Pachet;

public class NumerePrime { public boolean EstePrim(int n) { return true; } public int UrmatorulPrim(int n) { return 1; } public boolean Vecine(int n, int m) { return true; } }

c. Se salveaza fisierul NumerePrime.java 2. Se creaza fisierul UsePachet.java si se compileaza:


import Pachet.*; class UsePachet { public static void main (String args[]) { NumerePrime np = new NumerePrime(); System.out.println(np.EstePrim(3)); } }

Observatie: In momentul compilarii fisierului UsePachet.java se compileaza si fisierele (NumePrime.java) care fac parte din pachetul folosit in UsePachet.

Exercitiu
Se cere implementarea metodelor din clasa NumerePrime si apelarea lor in clasa UsePachet.

Laborator 3 Fluxuri
Majoritatea aplicatiilor necesita citirea unor informatii care se gasesc pe o sursa externa sau trimiterea unor informatii catre o destinatie externa. Informatia se poate gasi oriunde: intr-un fisier pe disc, in retea, in memorie sau in alt program si poate fi de orice tip: date primitive, obiecte, imagini, sunete, etc. Pentru a aduce informatii dintr-un mediu extern, un progam Java trebuie sa deschida un canal de comunicatie (flux) de la sursa informatiilor (fisier, memorie, socket, etc) si sa citeasca secvential informatiile respective. Indiferent de tipul informatiilor, citirea/scrierea de pe/catre un mediu extern respecta urmatorul algoritm:
deschide canal comunicatie while (mai sunt informatii) { citeste/scrie informatie; } inchide canal comunicatie;

Atat sursa externa a unor date cat si destinatia lor sunt vazute ca fiind niste procese care produc, respectiv consuma informatii. Definitii: Un flux este un canal de comunicatie unidirectional intre doua procese. Un flux care citeste date se numeste flux de intrare. Un flux care scrie date se numeste flux de iesire. Observatii: Fluxurile sunt canale de comunicatie seriale pe 8 sau 16 biti. Fluxurile sunt unidirectionale, de la producator la consumator. Fiecare flux are un singur proces producator si un singur proces consumator. Intre doua procese pot exista oricate fluxuri, orice proces putand fi atat producator cat si consumator in acelasi timp, dar pe fluxuri diferite.

Fluxuri standard de intrare si iesire


In Java exista: o intrare standard o iesire standard o iesire standard pentru erori In general, intrarea standard este tastatura iar iesirea standard este ecranul. Intrarea si iesirea standard sunt reprezentate de obiecte pre-create ce descriu fluxuri de date care comunica cu dispozitivele standard ale sistemului.

Aceste obiecte sunt definite publice in clasa System si sunt: System.in - fluxul standar de intrare System.out - fluxul standar de iesire System.err - fluxul standar pentru erori Afisarea informatiilor pe ecran Afisarea oricaror rezultate pe ecran (in modul consola) se poate face cu ajutorul urmatoarelor metode:
System.out.print (argument); System.out.println(argument); System.out.printf (format, argumente...); System.out.format (format, argumente...);

Fluxul standard pentru afisarea erorilor se foloseste similar si apare de obicei in secventele de tratare a exceptiilor. Implicit, este acelasi cu fluxul standard de iesire.
catch(Exception e) { System.err.println("Exceptie:" + e); }

Citirea datelor de la tastatura Citirea datelor se poate face folosind metoda System.in.read(). De cele mai multe ori se foloseste metoda readLine impreuna cu o clasa de procesare care ofera aceasta metoda. Exemplul tipic este:
BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Introduceti o linie:"); String linie = stdin.readLine() System.out.println(linie);

Exemplul 1
class Input { public static void main(String args[]) throws java.io.IOException { byte zona[] = new byte[50]; System.in.read(zona); String sir = new String(zona,0); System.out.println(sir); } }

Exemplul 2
class Calc {

public static void main(String args[]) { System.out.println("Introduceti prima valoare"); int a = System.in.read(); System.out.println("Introduceti a doua valoare"); int b = System.in.read(); // Se calculeaza suma folosind metoda parseInt() a //clasei Integer int c = a + b; System.out.println("Suma este" +c); } }

Exemplul 3
import java.io.*; public class InputLinie { public static void main ( String [] args ) { BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Introduceti o linie:"); String linie = stdin.readLine() System.out.println(linie); } }

Exercitiu Scrieti un program in Java care sa citeasca o linie de la tastatura si sa determine daca linia reprezinta un numar sau nu.

Laborator 4 Fluxuri (continuare)


Clasificarea fluxurilor Exista trei tipuri de clasificare a fluxurilor: Dupa directia canalului de comunicatie deschis fluxurile se impart in: fluxuri de intrare (pentru citirea datelor) fluxuri de iesire (pentru scrierea datelor) Dupa tipul de date pe care opereaza: fluxuri de octeti (comunicarea seriala se realizeaza pe 8 biti) fluxuri de caractere (comunicarea seriala se realizeaza pe 16 biti) Dupa actiunea lor: fluxuri primare de citire/scriere a datelor (se ocupa efectiv cu citirea/scrierea datelor) fluxuri pentru procesarea datelor Clasele radacina pentru ierarhiile ce reprezinta fluxuri de caractere sunt: Reader - pentru fluxuri de intrare si Writer - pentru fluxuri de iesire. Acestea sunt superclase abstracte pentru toate clasele ce implementeaza fluxuri specializate pentru citirea/scrierea datelor pe 16 biti si vor contine metodele comune tuturor. Ca o regula generala, toate clasele din aceste ierarhii vor avea terminatia Reader sau Writer in functie de tipul lor, cum ar fi in exemplele: FileReader, BufferedReader, FileWriter, BufferedWriter, etc. Clasele radacina pentru ierarhia fluxurilor de octeti sunt: InputStream - pentru fluxuri de intrare si OutputStream - pentru fluxuri de iesire. Acestea sunt superclase abstracte pentru clase ce implementeaza fluxuri specializate pentru citirea/scrierea datelor pe 8 biti. Ca si in cazul fluxurilor pe caractere denumirile claselor vor avea terminatia superclasei lor: FileInputStream, BufferedInputStream, FileOutputStream, BufferedOutputStream, etc. Pentru majoritatea programelor este recomandat ca scrierea si citirea datelor sa se faca prin intermediul fluxurilor de caractere, deoarece acestea permit manipularea caracterelor Unicode in timp ce fluxurile de octeti permit doar lucrul pe 8 biti - caractere ASCII.

Fluxuri primitive
Fluxurile primitive sunt responsabile cu citirea/scrierea efectiva a datelor, punand la dispozitie implementari ale metodelor de baza read, respectiv write, definite in superclase. In functie de tipul sursei datelor, ele pot fi impartite astfel: Fisier FileReader, FileWriter FileInputStream, FileOutputStream Numite si fluxuri fisier, acestea sunt folosite pentru citirea datelor dintr-un fisier, respectiv scrierea datelor intr-un fisier. Memorie CharArrayReader, CharArrayWriter ByteArrayInputStream, ByteArrayOutputStream Aceste fluxuri folosesc pentru scrierea/citirea informatiilor in/din memorie si sunt create pe un vector existent deja. Cu alte cuvinte, permit tratarea vectorilor ca sursa/destinatie pentru crearea unor fluxuri de intrare/iesire. Pipe PipedReader, PipedWriter PipedInputStream, PipedOutputStream Implementeaza componentele de intrare/iesire ale unei conducte de date (pipe). Pipe-urile sunt folosite pentru a canaliza iesirea unui program sau fir de executie catre intrarea altui program sau fir de executie.

Crearea unui flux primitiv


Asadar, crearea unui flux primitiv de date care citeste/scrie informatii de la un dispozitiv extern are formatul general: FluxPrimitiv numeFlux = new FluxPrimitiv(dispozitivExtern);

Exemplul 1
import java.io.*; class CreareFisier { public static void main(String args[]) { FileOutputStream fdest; if (args.length !=1) {System.out.println("Utilizare:java CreareFisier destinatie"); System.exit(1); } try { fdest = new FileOutputStream(args[0]); char c; while ((c=(char)System.in.read()) != '\u001a') fdest.write((byte)c); fdest.close(); System.exit(0);

} catch(IOException e){} } }

Exemplul 2
import java.io.*; public class CopiereFisiere { static FileInputStream fsursa; static FileOutputStream fdest; public static void main( String args[]) { if (args.length != 2) { System.out.println("Utilizare: java CopiereFisiere sursa destinatie"); System.exit(1); } try { fsursa = new FileInputStream(args[0]); fdest = new FileOutputStream(args[1]); copiere(fsursa,fdest); fsursa.close(); fdest.close(); } catch (FileNotFoundException e) { System.out.println("Nu exista fisierul " + args[0]); System.exit(2); } catch (IOException e) { System.out.println(" Eroare copiere"); } } public static void copiere(InputStream sin, OutputStream sout) throws IOException { byte buffer[] = new byte[1024]; int bytesCititi; while( (bytesCititi = sin.read(buffer)) > 0) sout.write(buffer,0,bytesCititi); }

} Exercitiu Sa se realizeze un program care sa concateneze n fisiere. Programul se va apela astfel:


java Con fisier fisier1 fisier2 fisier3

In urma rularii programului, fisier va contine:

Continut fisier1 Continut fisier2 Continut fisier3

Laborator 5 Fluxuri de procesare


Fluxurile de procesare (sau de filtrare) sunt responsabile cu preluarea datelor de la un flux primitiv si procesarea acestora pentru a le oferi intr-o alta forma, mai utila dintr-un anumit punct de vedere. De exemplu, BufferedReader poate prelua date de la un flux FileReader si sa ofere informatia dintr-un fisier linie cu linie. Fiind primitiv, FileReader nu putea citi decat caracter cu caracter. Un flux de procesare nu poate fi folosit decat impreuna cu un flux primitiv. Clasele ce descriu aceste fluxuri pot fi impartite in functie de tipul de procesare pe care il efectueaza astfel: Bufferizare BufferedReader, BufferedWriter BufferedInputStream, BufferedOutputStream Sunt folosite pentru a introduce un buffer in procesul de citire/scriere a informatiilor, reducand astfel numarul de accesari la dispozitivul ce reprezinta sursa/destinatia originala a datelor. Sunt mult mai eficiente decat fluxurile fara buffer si din acest motiv se recomanda folosirea lor ori de cate ori este posibil. Filtrare FilterReader, FilterWriter FilterInputStream, FilterOutputStream Sunt clase abstracte ce definesc o interfata comuna pentru fluxuri care filtreaza automat datele citite sau scrise. Conversie octeti-caractere InputStreamReader, OutputStreamWriter Formeaza o punte de legatura intre fluxurile de caractere si fluxurile de octeti. Un flux InputStreamReader citeste octeti dintr-un flux InputStream si ii converteste la caractere, folosind codificarea standard a caracterelor sau o codificare specificata de program. Similar, un flux OutputStreamWriter converteste caractere in octeti si trimite rezutatul catre un flux de tipul OutputStream. Serializare ObjectInputStream, ObjectOutputStream Sunt folosite pentru serializarea obiectelor. Concatenare SequenceInputStream Concateneaza mai multe fluxuri de intrare intr-unul singur. Conversie tipuri de date DataInputStream, DataOutputStream Folosite la scrierea/citirea datelor de tip primitiv intr-un format binar, independent de masina pe care se lucreaza. Numarare LineNumberReader LineNumberInputStream Ofera si posibilitatea de numarare automata a liniilor citite de la un flux de intrare.

Fluxurile de procesare nu pot exista de sine statatoare ci se suprapun pe un flux primitiv de citire/scriere a datelor. Din acest motiv, constructorii claselor pentru fluxurile de procesare nu primesc ca argument un dispozitiv extern de memorare a datelor ci o referinta la un flux primitiv responsabil cu citirea/scrierea efectiva a datelor: Exemple:
//crearea unui flux de intrare printr-un buffer BufferedReader in = new BufferedReader(new FileReader("fisier.txt")); //echivalent cu FileReader fr = new FileReader("fisier.txt"); BufferedReader in = new BufferedReader(fr); //crearea unui flux de iesire printr-un buffer BufferedWriter out = new BufferedWriter(new FileWriter("fisier.txt"))); //echivalent cu FileWriter fo = new FileWriter("fisier.txt"); BufferedWriter out = new BufferedWriter(fo);

Asadar, crearea unui flux pentru procesarea datelor are formatul general: FluxProcesare numeFlux = new FluxProcesare(fluxPrimitiv); Exemplul 1
import java.io.*; class CitesteNumar { public static void main(String args[])throws IOException { int numar; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); System.out.print("Introduceti un numar intreg "); numar = new Integer(in.readLine()).intValue(); System.out.println("\nNumarul introdus este " + numar); } }

Exemplu 2
import java.io.*; class BufferedIO { public static void main(String args[]) { byte[] buf = new byte[1024]; int citit; try { FileInputStream fin = new FileInputStream(args[0]); FileOutputStream fout = new FileOutputStream(args[1]);

BufferedInputStream bfin = new BufferedInputStream(fin,4096); BufferedOutputStream bfout = new BufferedOutputStream(fout,2048); bfin.mark(128); citit = bfin.read(buf,0,128); bfout.write(buf,0,citit); bfin.reset(); while((citit = bfin.read(buf,0,1024)) != -1) bfout.write(buf,0,citit); bfout.flush(); bfin.close(); bfout.close(); } catch (FileNotFoundException e) { System.out.println("Nu exista fisierul sursa " + args[0]); } catch (IOException e1) { System.out.println("Eroare I/O"); } } }

Exemplu 3
import java.io.*; class ScriePrime { public static void main(String args[]) { int prime[] = new int[400]; int index = 0, nr = 2; while ( index < 400) { if (estePrim(nr)) prime[index++] = nr; nr++; } try { FileOutputStream fout = new FileOutputStream("NrPrime.dat"); BufferedOutputStream buffer = new BufferedOutputStream(fout); DataOutputStream date = new DataOutputStream(buffer); for(int i=0;i<400;i++) date.writeInt(prime[i]); date.close(); } catch(IOException e) { System.out.println("Eroare " + e); System.exit(1); } System.exit(0); } public static boolean estePrim(int nr) { double radical = Math.sqrt(nr); for(int i=2;i<= radical;i++) if (nr%i == 0) return false; return true; } }

Exercitiu Sa se citeasca din fisierul NrPrime.dat numerele prime care sunt mai mari decat 100 si mai mici de 200.

Laborator 6 Serializarea obiectelor


Definitie Serializarea este o metoda ce permite transformarea unui obiect intr-o secventa de octeti sau caractere din care sa poata fi refacut ulterior obiectul original. Acest lucru inseamna ca serializarea permite salvarea intr-o maniera unitara a tuturor informatiilor unui obiect pe un mediu de stocare extern programului. Procesul invers, de citire a unui obiect serializat pentru a-i reface starea originala, se numeste deserializare. Utilitatea serializarii consta in urmatoarele aspecte: Asigura un mecanism simplu de utilizat pentru salvarea si restaurarea datelor. Permite persistenta obiectelor, ceea ce inseamna ca durata de viata a unui obiect nu este determinata de executia unui program in care acesta este definit - obiectul poate exista si intre apelurile programelor care il folosesc. Acest lucru se realizeaza prin serializarea obiectului si scrierea lui pe disc inainte de terminarea unui program, apoi, la relansarea programului, obiectul va fi citit de pe disc si starea lui refacuta. Compensarea diferentelor intre sisteme de operare - transmiterea unor informatii intre platforme de lucru diferite se realizeaza unitar, independent de formatul de reprezentare a datelor, ordinea octetilor sau alte detalii specifice sistemelor repective. Transmiterea datelor in retea - Aplicatiile ce ruleaza in retea pot comunica intre ele folosind fluxuri pe care sunt trimise, respectiv receptionate obiecte serializate. RMI (Remote Method Invocation) - este o modalitate prin care metodele unor obiecte de pe o alta masina pot fi apelate ca si cum acestea ar exista local pe masina pe care ruleaza aplicatia. Atunci cand este trimis un mesaj catre un obiect remote (de pe alta masina), serializarea este utilizata pentru transportul argumentelor prin retea si pentru returnarea valorilor. Serializarea obiectelor se realizeaza prin intermediul fluxurilor definite de clasele ObjectOutputStream (pentru salvare) si ObjectInputStream (pentru restaurare). Clasele ObjectInputStream si ObjectOutputStream implementeaza interfetele ObjectInput, respectiv ObjectOutput care extind DataInput, respectiv DataOutput, ceea ce inseamna ca, pe langa metodele dedicate serializarii obiectelor, vor exista si metode pentru scrierea/citirea datelor primitive si a sirurilor de caractere.

Metodele pentru serializarea obiectelor sunt: writeObject, pentru scriere si readObject, pentru restaurare. Important! Un obiect este serializabil daca si numai daca clasa din care face parte implementeaza interfata Serializable.

Exemplu
//Punct.java import java.io.*; class Punct implements Serializable { int x,y; Punct(int x,int y) { this.x = x; this.y = y; } public String toString() { return "Punct(" + x + "," + y +")"; } } //Cerc.java import java.io.*; class Cerc implements Serializable { Punct p; int r; Cerc(int x,int y,int r) { p = new Punct(x,y); this.r = r; } public String toString() { return "Cerc(" + p.x + "," + p.y + "," + r + ")"; } } //ScrieObiecte.java import java.io.*; class ScrieObiecte { public static void main(String args[]) throws Exception { FileOutputStream fdest = new FileOutputStream("FisierObiecte"); ObjectOutputStream objdest = new ObjectOutputStream(fdest); objdest.writeObject(new Punct(5,10)); objdest.writeObject(new Cerc(3,5,10)); objdest.close(); } }

//CitesteObiecte.java import java.io.*; class CitesteObiecte { public static void main(String args[]) throws Exception { FileInputStream fsursa = new FileInputStream("FisierObiecte"); ObjectInputStream objsursa = new ObjectInputStream(fsursa); Punct p = (Punct) objsursa.readObject(); System.out.println(p.toString()); Cerc c = (Cerc) objsursa.readObject(); System.out.println(c.toString()); objsursa.close(); System.out.println("Again " + p + "\n" + c); } }

Exercitiu Sa se salveze intr-un fisier 5 obiecte din clasa Angajat de mai jos apoi sa se restaureze cele 5 obiecte si sa se calculeze salarul mediu.
class Angajat { String cnp; String nume; float salar; Angajat(String cnp, String nume, float salar) { this.cnp = cnp; this.nume = nume; this.salar = salar; } }

Laborator 7 Fisiere cu access direct (Clasa RandomAccessFile)


Fluxurile sunt procese secventiale de intrare/iesire. Acestea sunt adecvate pentru lucrul cu medii secventiale de memorare a datelor, cum ar fi pentru transmiterea informatiilor prin retea, desi sunt foarte utile si pentru dispozitive in care informatia poate fi accesata direct. Clasa RandomAccesFile are urmatoarele caracteristici: permite accesul nesecvential (direct) la continutul unui fisier; este o clasa de sine statatoare, subclasa directa a clasei Object; se gaseste in pachetul java.io; implementeaza interfetele DataInput si DataOutput, ceea ce inseamna ca sunt disponibile metode de tipul readXXX, writeXXX, intocmai ca la clasele DataInputStream si DataOutputStream; permite atat citirea cat si scriere din/in fisiere cu acces direct; permite specificarea modului de acces al unui fisier (read-only, readwrite). Constructorii acestei clase sunt:
RandomAccessFile(StringnumeFisier, StringmodAcces) throws IOException RandomAccessFile(StringnumeFisier, StringmodAcces) throws IOException

unde modAcces poate fi: r - fisierul este deschis numai pentru citire (read-only) rw - fisierul este deschis pentru citire si scriere (read-write) Exemple:
RandomAccesFile f1 = //deschide un fisier RandomAccesFile f2 = //deschide un fisier new RandomAccessFile("fisier.txt", "r"); pentru citire new RandomAccessFile("fisier.txt", "rw"); pentru scriere si citire

Clasa RandomAccesFile suporta notiunea de pointer de fisier. Acesta este un indicator ce specifica pozitia curenta in fisier. La deschiderea unui fisier pointerul are valoarea 0, indicand inceputul fisierului. Apeluri la metodele de citire/scriere deplaseaza pointerul fisierului cu numarul de octeti cititi sau scrisi de metodele respective. In plus fata de metodele de tip read si write clasa pune la dispozitie si metode pentru controlul pozitiei pointerului de fisier. Acestea sunt: skipBytes - muta pointerul fisierului inainte cu un numar specificat de octeti seek - pozitioneaza pointerului fisierului inaintea unui octet specificat getFilePointer - returneaza pozitia pointerului de fisier.

Exemplu 1
import java.io.*; public class RandAccessFile{ public static void main(String[] args) throws IOException{ BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Enter File name : "); String str = in.readLine(); try{ //Se deschide fisierul pentru citire si scriere RandomAccessFile rand = new RandomAccessFile(file,"rw"); //Se deplaseaza poiterul la sfarsitul fisierului rand.seek(file.length()); //Se scrie la sfarsitul fisierului rand.writeBytes("Clasa RandomAccessFile"); rand.close(); System.out.println("Informatie scrisa cu success!"); } catch(IOException e) { System.out.println(e.getMessage()); } } }

Exemplu 2
import java.io.*; import java.util.*; class RAFisier { public static void main(String args[]) throws IOException { RandomAccessFile fis; int i; long pozitie; fis = new RandomAccessFile("Double.dat","rw"); Random r = new Random(1000); for(i = 0;i < 10;i++)

fis.writeDouble(r.nextDouble()); System.out.println("Fisierul este"); fis.seek(0); for(i = 0;i < 10;i++) System.out.print(fis.readDouble() + "\t"); System.out.println("Modific aleator 3 inregistrari"); System.out.println("Pozitiile modificate"); r = new Random(); for(i = 0;i < 3;i++) { pozitie = r.nextLong(); if(pozitie < 0) pozitie = -pozitie; pozitie %= 10; System.out.print(pozitie + " "); fis.seek(8*pozitie); fis.writeDouble(1.0); } System.out.println("\nFisierul modificat"); fis.seek(0); for(i = 0;i < 10;i++) System.out.print(fis.readDouble() + "\t"); fis.close(); } }

Exercitiu Realizati un program care sa inlocuiasca cu caracterul * fiecare aparitie a unui cuvant dat intr-un fisier. Exemplu de folosire:
>java replace fisier.txt cuvant

Laborator 8 Structuri de date in Java


//NodLista.java class NodLista implements java.io.Serializable { protected Object val = null; protected NodLista prec = null; protected NodLista urm = null; public NodLista(Object obj) { if (obj == null) throw new NullPointerException(); val = obj; } } //Lista.java class Lista { protected NodLista cap = null; protected NodLista coada = null; protected int nrElem = 0; public boolean esteGoala() { return cap == null; } private NodLista gaseste(Object obj) { if( esteGoala() || obj == null) return null; NodLista temp = cap; while(temp != null) { if(temp.val.equals(obj)) return temp; temp = temp.urm; } return null; } public boolean contine(Object obj) { return gaseste(obj) != null; } public void adauga(Object obj) { if(obj == null) throw new NullPointerException(); NodLista nod = new NodLista(obj); nrElem++; if(cap == null) { cap = nod; coada = nod; } else { coada.urm = nod; nod.prec = coada;

coada = nod; } } public void insereaza(Object obj,Object poz) { if(obj == null || poz == null) throw new NullPointerException(); NodLista pozNod = gaseste(poz); if(pozNod == null) throw new NullPointerException(); NodLista nod = new NodLista(obj); nrElem++; nod.urm = pozNod; nod.prec = pozNod.prec; if(pozNod == cap) cap = nod; else pozNod.prec.urm = nod; pozNod.prec =nod; } public boolean sterge(Object obj) { if(obj == null) throw new NullPointerException(); NodLista stergNod = gaseste(obj); if(stergNod == null) return false; nrElem--; if(stergNod == cap) cap = stergNod.urm; else stergNod.prec.urm = stergNod.urm; if(stergNod == coada) coada = stergNod.prec; else stergNod.urm.prec = stergNod.prec; return true; } } //ScrieLista.java import java.io.*; class ScrieLista { public static void main(String args[]) throws Exception { Lista lista = new Lista(); for(int i = 0;i < 5;i++) lista.adauga(new Integer(i)); FileOutputStream fdest = new FileOutputStream("FisierLista"); ObjectOutputStream objdest = new ObjectOutputStream(fdest); objdest.writeObject(lista.cap); objdest.writeObject(lista.coada); objdest.close(); } }

Exercitiu Sa se citeasca valorile din lista salvata in fisierul FisierLista.

Laborator 9 Iteratori si enumerari


Definitie Enumerarile si iteratorii descriu modalitati pentru parcurgerea secventiala a unei colectii, indiferent daca aceasta este indexata sau nu. Ei sunt descrisi de obiecte ce implementeaza interfetele Enumeration, respectiv Iterator sau ListIterator. Toate clasele care implementeaza colectii au metode ce returneaza o enumerare sau un iterator pentru parcurgerea elementelor lor. Deoarece functionalitatea interfetei Enumeration se regaseste in Iterator, aceasta din urma este preferata in noile implementari ale colectiilor. Metodele uzuale ale acestor interfete sunt prezentate mai jos, impreuna cu modalitatea lor de folosire: Enumeration: hasMoreElements, nextElement
// Parcurgerea elementelor unui vector v Enumeration e = v.elements; while (e.hasMoreElements()) { System.out.println(e.nextElement()); } // sau, varianta mai concisa for (Enumeration e = v.elements(); e.hasMoreElements();) { System.out.println(e.nextElement()); }

Iterator: hasNext, next, remove


// Parcurgerea elementelor unui vector // si eliminarea elementelor nule for (Iterator it = v.iterator(); it.hasNext();) { Object obj = it.next(); if (obj == null) it.remove(); }

ListIterator: hasNext, hasPrevious, next, previous, remove, add, set


// Parcurgerea elementelor unui vector // si inlocuirea elementelor nule cu 0 for (ListIterator it = v.listIterator(); it.hasNext();) { Object obj = it.next(); if (obj == null) it.set(new Integer(0)); }

Iteratorii simpli permit eliminarea elementului curent din colectia pe care o parcurg, cei de tip ListIterator permit si inserarea unui element la pozitia curenta, respectiv modificarea elementului curent, precum si iterarea in ambele sensuri. Iteratorii sunt preferati enumerarilor datorita posibilitatii lor de a actiona asupra colectiei pe care o parcurg prin metode de tip remove, add, set. Atentie Deoarece colectiile sunt construite peste tipul de date Object, metodele de tip next sau prev ale iteratorilor vor returna tipul Object, fiind responsabilitatea noastra de a face conversie (cast) la alte tipuri de date, daca este cazul.

Exemplu
//ListaIterator.java import java.util.*; class ListaIterator implements Enumeration { protected NodLista poz; public ListaIterator(Lista lista) { poz = lista.cap; } public boolean hasMoreElements() { return poz != null; } public Object nextElement() { if(poz == null) throw new NoSuchElementException(); NodLista temp = poz; poz = poz.urm; return temp.val; } } //CitesteLista.java import java.io.*; class CitesteLista { public static void main(String args[]) throws Exception { Lista lista = new Lista(); FileInputStream fsursa = new FileInputStream("FisierLista"); ObjectInputStream objsursa = new ObjectInputStream(fsursa); lista.cap = (NodLista)objsursa.readObject(); lista.coada = (NodLista)objsursa.readObject(); System.out.println("Lista contine:");

java.util.Enumeration e = new ListaIterator(lista); while(e.hasMoreElements()) { Integer element = (Integer)e.nextElement(); System.out.println(element.toString()); } } }

Exercitiu
//TestIterator.java import java.util.*; class TestIterator { public static void main ( String args []) { ArrayList a = new ArrayList (); // Adaugam numerele de la 1 la 10 for (int i=1; i <=10; i++) a.add(new Integer (i)); // Amestecam elementele colectiei Collections.shuffle(a); System.out.println (" Vectorul amestecat : " + a); // Parcurgem vectorul // Daca elementul curent este par , il facem 0 //... System . out. print (" Rezultat : " + a); } }

Sa se completeze exemplul de mai sus astfel incat dupa amestecarea elementelor vectorului a sa se parcurga vectorul folosind un iterator si sa se inlocuiasca fiecare valoare para cu 0. Observatie: clasa ArrayList implementeaza interfata ListIterator.

Laborator 10 Tehnici de programare Backtracking in Java


Metoda backtracking se poate aplica unui mare numr de probleme enumerative sau de optimizare cu solutie vectorial pentru c asigur obtinerea tuturor solutiilor posibile pentru problema dat. Totusi, ea se recomand numai problemelor pentru care nu se cunoaste un algoritm mai eficient (polinomial) sau problemelor de dimensiuni mici, la care timpul de rezolvare este nc acceptabil. Un algoritm backtracking este un algoritm de cutare sistematic si exhaustiv a tuturor solutiilor, dintre care se pot alege apoi solutiile acceptate. Cutarea exhaustiv n arborele de solutii este un proces de ncercare si revenire (de cutare cu revenire). Exemplu de implementare in Java
//Backtracking.java public abstract class Backtracking { abstract boolean conditieContinuare(); abstract boolean solutie(); abstract void nivelUrmator(); abstract void nivelAnterior(); abstract boolean existaUrmator(); abstract void elementUrmator(); abstract boolean sfarsitCautare(); public boolean cautaSolutie() { while(!sfarsitCautare()) { boolean gasit = false; while(existaUrmator() && !gasit) { elementUrmator(); if(conditieContinuare()) gasit = true; } if(gasit) if(solutie()) return true; else nivelUrmator(); else nivelAnterior(); } return false; } }

//Permutare.java public class Permutare extends Backtracking { int n; int k=0; int[] v; public Permutare(int n) { this.n = n; v = new int[n+1]; nivelUrmator(); } boolean conditieContinuare() { for(int i = 1;i < k;i++) if(v[i] == v[k]) return false; return true; } boolean solutie() { return k == n; } void nivelUrmator() { v[++k] = 0; } void nivelAnterior() { k--; } boolean sfarsitCautare() { return k == 0; } boolean existaUrmator() { return v[k] < n; } void elementUrmator() { v[k]++; } public void printSolutie() { for(int i =1; i<= n;i++) System.out.print(v[i] + " "); System.out.println(); } } //TestPermutare.java import java.io.*; class TestPermutare {public static void main(String args[])throws IOException { int n; System.out.println("Toate permutarile de n elemente"); InputStreamReader sin = new InputStreamReader(System.in);

BufferedReader in = new BufferedReader(sin); System.out.print("Introduceti (un numar intreg >=1) n = "); n = Integer.valueOf(in.readLine()).intValue(); Permutare p = new Permutare(n); while(p.cautaSolutie()) p.printSolutie(); } }

Exercitiu Modificati programul de mai sus pentru a rezolva problema celor 8 regine. Pentru a intelege mai bine problema vizitati: http://gaia.ecs.csus.edu/~wang/backtrack/queens/queen1/eightqueens.html

Laborator 11 Applet-uri
Un applet reprezinta un program Java de dimensiuni reduse ce gestioneaza o suprafata de afisare (container) care poate fi inclusa intr-o pagina Web. Un astfel de program se mai numeste miniaplicatie. Ca orice alta aplicatie Java, codul unui applet poate fi format din una sau mai multe clase. Una dintre acestea este principala si extinde clasa Applet, aceasta fiind clasa ce trebuie specificata in documentul HTML ce descrie pagina Web in care dorim sa includem appletul. Diferenta fundamentala dintre un applet si o aplicatie consta in faptul ca un applet nu poate fi executat independent, ci va fi executat de browserul in care este incarcata pagina Web ce contine appletul respectiv. Pachetul care ofera suport pentru crearea de appleturi este java.applet, cea mai importanta clasa fiind Applet. Pasi pentru realizarea un Applet simplu: 1. Scrierea codului sursa
import java.applet.Applet; import java.awt.Graphics; public class FirstApplet extends Applet { public void paint(Graphics g) { g.drawString("Hello First Applet!", 50, 25); } }

Pentru a putea fi executata de browser, clasa principala a appletului trebuie sa fie publica. 2. Salvarea fisierelor sursa Ca orice clasa publica, clasa principala a appletului va fi salvata intr-un fisier cu acelasi nume si extensia .java. Asadar, vom salva clasa de mai sus intr-un fisier FirstApplet.java. 3. Compilarea Compilarea se face la fel ca si la aplicatiile independente, folosind compilatorul javac apelat pentru fisierul ce contine appletul.

javac FirstApplet.java In cazul in care compilarea a reusit va fi generat fisierul FirstApplet.class. 4. Rularea applet-ului Applet-urile nu ruleaza independent. Ele pot fi rulate doar prin intermediul unui browser: Internet Explorer, Firefox, Opera, etc. Sau printr-un program special cum ar fi appletviewer din kitul de dezvoltare J2SDK. Pentru a executa un applet trebuie sa facem doua operatii: Crearea unui fisier HTML in care vom include applet-ul. Sa consideram fisierul simplu.html, avand continutul de mai jos:
<html> <head> <title>Primul applet Java</title> </head> <body> <applet code=FirstApplet.class width=400 height=400> </applet> </body> </html>

Vizualizarea appletului: se deschide fisierul simplu.html folosind unul din browser-ele amintite sau efectuand apelul: appletviewer simplu.html.

Exercitiu Sa se modifice applet-ul astfel incat sa se afiseze continutul unui fisier.

S-ar putea să vă placă și