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. Navigare http://java.sun.com/ si apoi se apasa meniul Downloads


2. Din Java SE se selecteaza Java SE(JDK)
3. Se apasa butonul de Download de langa JDK 6 Update 3.
4. Din pagina se selecteaza oricare din cele 2 optiuni de download.
5. 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 - operat¸ii 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 intefet¸ele 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 = new RandomAccessFile("fisier.txt", "r");
//deschide un fisier pentru citire
RandomAccesFile f2 = new RandomAccessFile("fisier.txt", "rw");
//deschide un fisier 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 numãr 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 cãutare sistematicã si exhaustivã a tuturor


solutiilor, dintre care se pot alege apoi solutiile acceptate. Cãutarea exhaustivã în arborele
de solutii este un proces de încercare si revenire (de cãutare 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