Limbaje de programare. Laborator 2-3 1. Clasa, obiect, abstractizare Clasa : descrie tipul obiectelor dintr-un program; poate fi asociată cu un şablon pentru crearea şi iniţializarea obiectelor în memorie; Obiectul: (sau instanţa) entitate bine determinată, construit conform definiţiei unei clase căruia i s-a alocat un anumit spaţiu în memoria calculatorului. Asemenea variabilelor care au identificator şi tip, obiectele au şi ele un identificator şi un tip, tipul fiind definit de către programator cu ajutorul claselor. Convenţii de reprezentare schematica claselor: Exemplu: Clasa masina definiţia tipului; Obiectul m de tipul sau din clasa Masina cu caracteristicile effective. Clasa/Tipul Obiectelor Obiectul/Instanta m în memorie Masina m= new Masina() Instanţiere (new) m.culoare = verde ; m.putere=100; m.marca= Ford ; m.an_fabricatie=2009 m.accelereaza(90); culoare: verde putere: 100 marca: Ford an_fabricatie: 2009 porneste() { opreste(){ accelereaza(90){ ->70 franeaza(100)->90 schimbaviteza(2,3){ schimba_directia( stanga ){
2. Operatorul de atribuire La atribuirea intre 2 variabile referinte catre obiecte, se face copierea intre referinte, ambele variabile referind acelasi obiect. class Tank { int level; public class Assignment { Tank t1 = new Tank(); //obiectul t1 din clasa Tank Tank t2 = new Tank(); //obiectul t2 din clasa Tank t1.level = 9; t2.level = 47; //t1.level:9, t2.level:47 System.out.println("1: t1.level: " + t1.level + ", t2.level: " + t2.level); //referinta catre t1 va pointa catre obiectul t2 t1 = t2; System.out.println("2: t1.level: " + t1.level + ", t2.level: " + t2.level); //t1.level = 27 va schimba valoarea level din t2 - atribuirea de mai sus t1.level = 27; System.out.println("3: t1.level: " + t1.level + ", t2.level: " + t2.level); //observam ca t1.level si t2.level au aceiasi valoare 3. Aliasing La trimiterea unui obiect ca si argument intr-o metoda, se intampla Aliasing, adica atat variabila din metoda cat si cea din exterior vor arata catre acelasi obiect class Letter { char c; public class PassObject { static void f(letter y) { y.c = 'z'; Letter x = new Letter(); //creare obiect x din clasa Letter x.c = 'a'; System.out.println("1: x.c: " + x.c); //x.c are valoarea a f(x); //aliasing System.out.println("2: x.c: " + x.c); //x.c are valoare z - se trimite referinta la obiect ca si parametru si nu o copie a obiectului
4. Operatori pe String: + si += public class StringOperators { int x = 0, y = 1, z = 2; String s = "x, y, z "; System.out.println(s + x + y + z); System.out.print(x + " " + s); // conversie implicita a valorii x de la tipul int la string s += "(summed) = "; // echivalent cu s=s+"(summed)=" System.out.println(s + (x + y + z)); System.out.print("" + x); // Shorthand for Integer.toString()-metoda de conversie a int->string 5. Foreach selecteaza un element dintr-un array (vezi Eckel:Controlling Execution pag 93) import java.util.*; public class ForEachFloat { Random rand = new Random(47); //obiect ce genereaza numere random float f[] = new float[10]; // crearea arrayului de numere reale for(int i = 0; i < 10; i++) */ f[i] = rand.nextfloat(); // initializarea fiecarui element din array - parcurgere for(float x : f) //parcurgere vector f element cu element System.out.println(x); /*echivalent cu: for(int i=0;i<f.length;i++) * { * x=f[i]; System.out.println(x); * 6. Instructiuni pentru controlul fluxului programului (vezi Eckel:Controlling Execution pag 93) Scrieti un program care genereaza 25 de numere random intregi (clasa Random). Pentru fiecare din aceste numere utilizati o instructiune if-then-else pentru a testa daca numarul generat este mai mare, mai mic sau egal cu urmatorul numar intreg generat random. 7. Exercitii Creati un program care citeste ca si intrare un numar intreg si afiseaza toate numele lui Fibonacci cel mult egale cu numarul intreg citit la intrare. De exemplu, pentru valoarea 5 se afiseaza lista 1, 1, 2, 3, 5. Sirul lui Fibonacci: F n = F n-1 + F n-2, F 0 =0, F 1 =1, n=2,n.
8. Constructori metode speciale fara tip de return care initializeaza obiectele in momentul crearii lor cu new; Un constructor se apeleaza automat in momentul crearii unui obiect cu new. (vezi Eckel: Guaranteed initialization with the constructor pag 107) // Constructorii pot fi cu sau fara argumente. class Rock2 { Rock2(int i) { //constructor cu argumente System.out.println("Rock " + i + " "); public class SimpleConstructor2 { Rock2 obj; for(int i = 0; i < 8; i++) obj=new Rock2(i); //se creaza 8 obiecte din clasa Rock. //ca instantierea se face cu trimiterea argumentului i - asa cum o cere constructorul Rock2 //se vor afisa 8 mesaje - deoarece se va apela de 9 ori constructorul Rock2(int i) 9. Supraincarcarea metodelor intr-o clasa putem avea acelasi identifcator (nume) utilizat la definirea mai multor metode, dar fiecare metoda trebuie sa difere prin tipul a cel putin unui argument si sa aiba acelasi tip de return. //: initialization/overloading.java // Constructorii pot fi supraincarcati //metodele dintr-o clasa pot fi supraincarcate class Tree { int height; Tree() { //constructor implicit fara argumente System.out.println("Planting a seedling"); height = 0; Tree(int initialheight) { //acelasi constructor Tree supraincarcat cu un argument height = initialheight; System.out.println("Creating new Tree that is " + height + " feet tall"); //constructorii supraincarcati ofera flexibilitate in initialirea obiectelor void info() { //metoda info fara argumente cu tip de return void System.out.println("Tree is " + height + " feet tall"); void info(string s) { //metoda info cu argumente cu tip de return void System.out.println(s + ": Tree is " + height + " feet tall");
public class Overloading { for(int i = 0; i < 5; i++) { Tree t = new Tree(i); //instantiere utilizand constructorul supraincarcat cu un argument t.info(); //apel metoda info() fara argumente t.info("overloaded method"); //apel metoda info cu argument // Overloaded constructor: Tree t=new Tree(); //instantierea obiectului t prin constructorul fara argument 10. Utilizarea this //: initialization/leaf.java // Simple use of the "this" keyword. public class Leaf { //clasa Leaf int i = 0; //atribut in clasa Leaf Leaf increment() { //metoda ce returneaza un obiect de tip Leaf i++; return this; // se returneaza obiectul curent void print() { //metoda in clasa Leaf System.out.println("i = " + i); Leaf x = new Leaf(); //instantiere x.increment().increment().increment().print(); //3 apeluri ale metodei increment //fiecare apel al metodei increment schimba valoarea atributlui i si returneaza obiectul cu noua valoare //fiecare apel increment() returneaza un obiect de tip Leaf 11. Utilizarea finalize In programul de mai jos, se presupune ca o carte (Book) trebuie sa fie in mod necesar checkin inainte ca aceasta sa fie distrusă. Observam ca exista o carte pentru care nu se face checkin si la apelul fortat al garbage collectorului, va aparea mesajul de eroare din finalize. class Book { boolean checkedout = false; Book(boolean checkout) { //constructor cu argument checkedout = checkout; //initializeaza atributul checkedout cu valoarea trimisa prin argument
void checkin() { //metoda checkin checkedout = false; protected void finalize() { //utilizarea finalize in clasa Book //inainte de distrugerea obiectelor cu garbage collector se va apela metoda finalize() if(checkedout) //daca atributul checkedout e True - se afiseaza eroare System.out.println("Error: checked out"); // Normally, you ll also do this: // super.finalize(); // Call the base-class version public class TerminationCondition { Book novel = new Book(true); //creare obiect novel de tip Book // Proper cleanup: novel.checkin(); //dupa utilizare - se da checkin() - obiectul se poate sterge // Drop the reference, forget to clean up: new Book(true); //se creaza un nou obiect din clasa Book // Force garbage collection & finalization: System.gc(); //se apeleaza garbage collector - ce determina executia finalize() din clasa Book //pentru ca la cel de-al doilea obiect nu s-a apelat metoda checkin() - se va afisa mesajul de eroare // 12. Ordinea de initializare ordinea in care datele member/atributele sunt definite in clasa // When the constructor is called to create a // Window object, you ll see a message: class Window { Window(int marker) //constructor { System.out.println("Window(" + marker + ")"); class House { Window w1 = new Window(1); // (1) initializare (apelul constructorului Window din clasa Window) // se face inainte de apelul constructorului House() House() { //constructor in clasa House() // Show that we re in the constructor: System.out.println("House()"); w3 = new Window(33); // (4) reinitializare w3 dupa ce ultima initializare implicita a avut loc (pct. 3) Window w2 = new Window(2); // (2) initializare inainte de apelul constructorului House() void f() { System.out.println("f()"); // (3) ultima initializare implicita - inainte de apelul constructorului House()
Window w3 = new Window(3); public class OrderOfInitialization { //instantierea House (apelul constructorului House()) determina initializarea in ordinea de mai sus House h = new House(); h.f(); // Shows that construction is done 13. Initializarea static atributele statice se initializeaza o singura data; daca acestea au fost deja intializate, ele nu se reinitializeaza. class Bowl { Bowl(int marker) { //constructor in clasa Bowl System.out.println("Bowl(" + marker + ")"); void f1(int marker) { //metoda in clasa Bowl System.out.println("f1(" + marker + ")"); class Table { static Bowl bowl1 = new Bowl(1); //(init.1) membru static de tip Bowl in clasa Table Table() { //apelul constr. se face dupa initializarea atributelor statice din clasa System.out.println("Table()"); bowl2.f1(1); //apel catre f1 din constructor void f2(int marker) { //metoda in clasa Table System.out.println("f2(" + marker + ")"); static Bowl bowl2 = new Bowl(2); //(init. 2)membru static de tip Bowl in clasa Table class Cupboard { //initializarea membrilor non-statici se face dupa initializarea celor statici din clasa Bowl bowl3 = new Bowl(3); //membru non static de tip Bowl in Cupboard static Bowl bowl4 = new Bowl(4); //(init.3)membru static de tip Bowl in clasa CupBoard Cupboard() { //constructor in Cupboard System.out.println("Cupboard()"); bowl4.f1(2); void f3(int marker) { System.out.println("f3(" + marker + ")"); static Bowl bowl5 = new Bowl(5);//(init. 4) membru static
public class StaticInitialization { System.out.println("Creating new Cupboard() in main"); new Cupboard(); System.out.println("Creating new Cupboard() in main -!!!atributele statice nu mai sunt initializate"); new Cupboard(); //!!! la a doua instantiere se initializeaza doar atributele non-statice table.f2(1); cupboard.f3(1); static Table table = new Table(); static Cupboard cupboard = new Cupboard(); Astfel ordinea de initializare a a atributelor in clasa devine: Se initializeaza atributele/obiectele statice in ordinea in care apar in clasa, daca acestea nu au fost anterior initializate. Se initializeaza atributele/obiectele non-statice in ordinea in care apar in clasa. Cuvantul static se poate aplica numai atributelor din clase si nu variabilelor locale. Daca un atribut nu este initializat explicit, atunci Java asigura initializarea cu valoarea implicita a tipului (ex: Int: 0), pentru obiecte, aceasta fiind null. 14. Initializarea prin explicit static class Cup { Cup(int marker) { System.out.println("Cup(" + marker + ")"); void f(int marker) { System.out.println("f(" + marker + ")"); class Cups { static Cup cup1; static Cup cup2; static { // blocul static explicit de initializare cup1 = new Cup(1); cup2 = new Cup(2); Cups() { System.out.println("Cups()"); public class ExplicitStatic {
System.out.println("Inside main()"); Cups.cup1.f(99); // (1) //acces la membrii statici fara instantiere //initializarea statica se face si in acest caz - prin simpla referire //initializarea statica se face inainte de instantiere - la incarcarea clasei //static Cups cups1 = new Cups(); // (2) //static Cups cups2 = new Cups(); // (2) 15. Initializare non-statica mecanism denumit instance-initialization initializare la nivel de instanta //: initialization/mugs.java // Java "Instance Initialization." class Mug { Mug(int marker) { System.out.println("Mug(" + marker + ")"); void f(int marker) { System.out.println("f(" + marker + ")"); public class Mugs { Mug mug1; Mug mug2; { // bloc non-static de initializare - se face la fiecare instantiere cu new a clasei mug1 = new Mug(1); mug2 = new Mug(2); System.out.println("mug1 & mug2 initialized"); Mugs() { System.out.println("Mugs()"); Mugs(int i) { System.out.println("Mugs(int)"); System.out.println("Inside main()"); Mugs o1 = new Mugs(); //determina initializare a atributelor in o1 System.out.println("new Mugs() completed"); Mugs o2 = new Mugs(1); //determina reinitializarea atributelor in o2 (o1 raman neschimbate) System.err.println("new Mugs(1) completed"); //o1 si o2 sunt doua obiecte distincte (instante ale clasei Mugs) //a caror atribute non-statice pot lua valori diferite in fiecare obiect
16. Initializarea sirurilor de obiecte Creati un sir de obiecte de tip String si initializati fiecare obiect din sir. Tipariti sirul folosind un for. Creati o clasa care are un constructor cu un argument de tip String. In constructor, tipariti valoarea primita ca si argument. Creati un sir de referinte catre obiecte din clasa creata, dar fara a crea obiectele din sir. La executia programului, vedeti daca mesajul din constructor este tiparit. Initializati sirul cu obiecte din clasa creata.