Laborator 7

1. Polimorfism

2. Colectii de obiecte in Java

3. Ierarhia Collection

4. Iteratori

5. Ierarhia Map

6. Teme

 


Laborator 7.

 

1. Polimorfism

Polimorfismul permite folosirea unui obiect in locul altui obiect (o unei subclase in locul unei superclase). Prin aceasta sprijina scrierea de cod eficient cu costuri de dezvoltare si intretinere reduse.

Este sustinut doar de limbajele care permit “legarea intarziata” la apelul metodelor. Acest lucru se refera la modalitatea in care sunt generate in programul executabil apelul rutinelor din program.

La limbajele cu "legare timpurie" adresa la care se face un apel spre o rutina se stabileste la compilare si este scrisa in mod univoc in codul obiect rezultat.

La limbajele cu legare intarziata, adresa de apel a unei rutine (metode in cazul Java) se stabileste doar in momentul rularii, functie de contextul in care apare apelul. In acest fel, spre exemplu, daca se declara o referinta spre o clasa Persoana care indica spre un obiect de tip Student, un apel al metodei afiseaza_date() va apela corect metoda cu acest nume din clasa Student si pe cea din Persoana.

Pentru exemplificare se considera exemplul din figura urmatoare:

      

Clasa Bird este o clasa abstracta care modeleaza conceptul de pasare. Din ea sunt derivate doua clase concrete si anume Goose (gasca) si Penguin (pinguin).

Pentru gestionarea migratiei pasarilor se foloseste o clasa separata numita BirdControler. Aceasta clasa pune la dispozitie o metoda pentru realizarea migrarii denumita reLocate(). Problema rezida in a realiza corect deplasarea. In acest sens Gasca poate implementa move() prin apelulul metodei proprii zboara(). Analog, Pinguinul poate implementa move() prin apelulul metodei proprii inoata(). In momentul cand este apelata metoda reLocate() din BirdControler, aceasta va invoca corect metodele move() din subclasele clasei Bird. Rezultatul este ca pinguinul va inota iar gasca va zbura pentru a reliza migrarea, chiar daca clasa BirdControler pastreaza referinte doar spre clasa Bird.

Din acest exeplu rezulta de asemenea avantaje la nivelul implementarii si testarii. Informatii despre o noua pasare pot fi adaugate simplu, fara a modifica clasa BirdControler. In acest sens este suficient sa se deriveze o noua clasa din Bird, iar aceasta sa implementeze propria metoda move(). Este evident ca adaugarea acestei clase nu introduce erori in clasele existente deja, ca atare codul care implementeaza procesul de migratie nu mai trebuie retestat.

Polimorfismul se utilizeaza des pentru a trata unitar colectii de obiecte diferite. Un exemplu in acest sens este tablou de Aparate din laboratorul referitor la Interfete Java.

      

Datorita suportului pentru polimorfism, urmatoarea secventa de cod apeleaza corect metoda proprie de pornire a fiecarui aparat in parte:

Aparat aparate[] = new Aparat[6];
aparate[0] = new Fax(1440, 230);
aparate[1] = new Calculator(1200, 256, 350);
aparate[2] = new Monitor(17, 130);
aparate[3] = new Radio("Panasonic", 80);
aparate[4] = new Bec(200);
aparate[5] = new Radiator(2000);

for (i=0; i<aparate.length; i++)
                  aparate[i].porneste();

Referinta: Interfete.java.

2. Colectii de obiecte in Java

Aproape toate programele reale utilizeaza colectii de obiecte. De asemenea, toate limbajele de programare de nivel inalt implementeaza intr-o forma sau alta tipul array (tablou de elemente).

In Java, variabilele de tip array sunt considerate obiecte, avand asociate, pe langa setul de elemente continute si un atribut length care da informatii despre numarul de elemente si o metoda clone() care ofera posibilitatea crearii unei copy a tabloului original.

Pe langa tipul array, pentru gestionarea acestor colectii de obiecte limbajul Java pune la dispozitie clase specializate, reunite in pachetul java.util. Acest pachet contine doua ierarhii principial diferite: Collection (multimi de obiecte) si Map (seturi tip cheie->valoare).

3. Ierahia Collection

Ierarhia derivata din Collection cuprinde doua tipuri de clase:

  • List (permite duplicate, defineste o ordonare a elementelor)
  • Set (nu permite duplicate)

Din ierarhia List fac parte: ArrayList si LinkedList.

Ierarhia Set cuprinde: HashSet si TreeSet.

Metode definite de interfata comuna Collection:

  1. add(), addAll() - adauga la colectie obiectul transmis, respectiv toate elementele colectiei transmise
  2. clear() - goleste colectia
  3. contains(), containsAll() - verifica daca in colectie se gaseste obiectul transmis, respectiv daca in colectie este inclusa colectia transmisa
  4. remove() - elimina obiectul dat ca si parametru
  5. toArray() creaza un tablou continand elementele colectiei
  6. size() – returneaza numarul de elemente al colectiei

Metode definite de interfata List:

  1. addFirst() – adauga un element la inceputul listei
  2. addLast() – adauga un element la sfarsitul listei
  3. getFirst() – intoarce primul element din lista
  4. getLast() – intoarce ultimul element din lista
  5. removeFirst() – sterge primul element din lista
  6. removeLast() - sterge ultimul element din lista

Clasele care implementeaza aceasta interfata sunt ArrayList (pentru situaltiile cand se doreste acces aleator la elemente), LinkedList (pentru situatiile cand se efectuaeaza acces secvential la elementele listei). Un caz special Vector, derivata din AbstractList si care implementeaza un tablou unidimensional dinamic, adaugand la tipul array o metoda setSize() care redimensioneaza tabloul cand este necesar.

Exemplu de utilizare liste pentru implementarea unei stive (structura LIFO - last in, first out):

Activitate:

Compilati si rulati programul urmator (fisierul Stiva.java).

import java.util.*;

/**
* Stiva - clasa pentru exemplificarea implementarii unei stive
* de numere intregi
* LIFO (last in - first out (primul intrat, ultimul extras))
*
* @version 1.0 03 Apr 2003
* @author Dan Pescaru
*/
class Stiva extends LinkedList {

   public Stiva() {
      super();
   }

   public void adauga(int nr) {
      Integer n = new Integer(nr);
      addFirst(n);
   }

   public void afiseaza() {
      System.out.print("Continutul stivei:");
      System.out.println(this);
   }

   public Integer extrage() {
      return (Integer)removeFirst();
   }

   public static void main(String args[]) {
      Stiva stiva = new Stiva(); // declarare stiva

      stiva.adauga(3);
      stiva.afiseaza();
      stiva.adauga(8);
      stiva.afiseaza();
      stiva.adauga(5);
      stiva.afiseaza();
      stiva.adauga(1);
      stiva.afiseaza();

      Integer i = stiva.extrage(); //se extrage ultimul adaugat
      System.out.println("S-a extras elemtul: "+i);
      stiva.afiseaza();
   }
}

Metode definite de interfata Set:

  1. add() – adauga un element la multime (daca nu exista)
  2. addAll() – adauga o colectie de elemente la multime
  3. contains() – verifica apartenenta unui element la multime
  4. isEmpty() – true daca multimea este vida
  5. remove () – sterge elementul specificat, daca exista
  6. removeAll() - sterge o colectie de elemente din multime

Clasele care implementeaza aceasta interfata sunt HashSet (implementare rapida) si TreeSet (pentru acces ordonat la elementele multimii).

Exemplu de utilizare multimi:

Activitate:

Compilati si rulati programul urmator (fisierul MultimeAnimale.java).

import java.util.*;

/**
* MultimeAnimale - clasa pentru exemplificarea implementarii unei
* multimi de animale
*
* @version 1.0 03 Apr 2003
* @author Dan Pescaru
*/
class MultimeAnimale extends HashSet {

   public MultimeAnimale() {
      super();
   }

   public void adauga(String animal) {
      add(animal);
   }

   public void afiseaza() {
      System.out.print("Animalele retinute:");
      System.out.println(this);
   }

   public void afiseazaOrdonat() {
      System.out.print("Animalele ordonate alfabetic:");
      System.out.println(new TreeSet(this));
   }

   public static void main(String args[]) {
      MultimeAnimale multimeAnimale = new MultimeAnimale();

      multimeAnimale.adauga("Urs");
      multimeAnimale.adauga("Rinocer");
      multimeAnimale.adauga("Viezure");
      multimeAnimale.adauga("Cerb");
      multimeAnimale.adauga("Lup");
      multimeAnimale.adauga("Bizon");

      multimeAnimale.afiseaza();
      multimeAnimale.afiseazaOrdonat();
   }
}

 

4. Iteratori

Pentru a aprcurge elementele unei multimi care implementeaza interfata Collection se pot utiliza structuri de date suplimentare numite iteratori.

Un iterator este un obiect care poate realiza traversarea in ordine a colectiei la care este atasat. Ordinea de parcurgere este determinata de maniera in care sunt retinute elementele in colectie.

Interfata Iterator contine urmatoarele declaratii:
   interface Iterator {
      boolean hasNext();
      Object next();
      void remove();
   }

Metoda iterator() declarata in interfata Collection creaza si returneaza referinta la un iterator asociat cu colectia curenta.

Utilizarea unui iterator se realizeaza dupa modelul:

Collection colectie = new ...
Iterator iteratorColectie = colectie.iterator();
...
while( iteratorColectie.hasNext()) {
   TipObject element = (TipObiect)iteratorColectie.next();
   // prelucrare element curent
   // ex. afisare: System.out.println(element);
}

Activitate:

Compilati si rulati programul urmator (fisierul MultimeAnimale1.java).

import java.util.*;

/**
* MultimeAnimale1 - clasa pentru exemplificarea implementarii unei
* multimi de animale parcursa printr-un iterator
*
* @version 1.0 03 Apr 2003
* @author Dan Pescaru
*/
class MultimeAnimale1 extends HashSet {

   ...

   public void afiseaza() {
      Iterator iteratorAnimale = this.iterator();

      System.out.println("Animalele retinute: { ");
      while( iteratorAnimale.hasNext()) {
         String animal = (String)iteratorAnimale.next();
         System.out.println("-> "+animal);
      }
      System.out.println(" }");
   }

   ...
}

5. Ierahia Map

Ierarhia Map are de asemenea doua tipuri:

  • HashMap (cheile nu sunt ordonate, prelucrarea este rapida)
  • TreeMap (cheile sunt ordonate in ordine ascendenta rezultand o viteza mai mica de prelucrare)

Metode definite de interfata Map:

  1. clear() – goleste multimea
  2. put() – adauga un obiect asociat unei chei
  3. containsKey() – verifica existenta unei chei
  4. containsValue() – verifica existenta unui obiect
  5. get() – returneaza obiectul asociat unei chei
  6. isEmpty() – true daca multimea este vida
  7. remove () – sterge cheia specificata
  8. size() – returneaza numarul de elemente

Clasele care implementeaza aceasta interfata sunt HashMap (implementare rapida, fara ordonare) si TreeMap (cheile ordonate crescator).

Activitate:

Compilati si rulati programul urmator (fisierul Dictionar.java).

import java.util.*;
import java.io.*;

/**
* Dictionar - clasa pentru exemplificarea implementarii unei
* multimi de tip map care asociaza cuvinte de explicatiile lor
*
* @version 1.0 03 Apr 2003
* @author Dan Pescaru
*/
public class Dictionar extends TreeMap{

   public Dictionar() {
      super();
   }

   public void adaugaCuvant(String cuvant, String explicatie) {
      Object vechi = put(cuvant, explicatie);
      if(vechi != null)
            System.out.println("Explicatia a fost schimbata!");
      else
            System.out.println("cuvantual a fost adaugat!");
   }

   public String cautaCuvant(String cuvant) {
      return (String)get(cuvant);
   }

   public void afisDictionar() {
      System.out.println(this);
   }


   public static void main(String args[]) throws Exception {
      Dictionar dict = new Dictionar();
      char raspuns;
      String linie, explic;
      BufferedReader fluxIn = new BufferedReader(new InputStreamReader(System.in));

      do {
         System.out.println("Meniu");
         System.out.println("a - adauga cuvant");
         System.out.println("c - cauta cuvant");
         System.out.println("l - listeaza dictionar");
         System.out.println("e - iesi");

         linie = fluxIn.readLine();
         raspuns = linie.charAt(0);

         switch(raspuns) {
            case 'a': case 'A':
               System.out.println("Citeste cuvant:");
               linie = fluxIn.readLine();
               if( linie.length()>1) {
                  System.out.println("Citeste exmplic:");
                  explic = fluxIn.readLine();
                  dict.adaugaCuvant(linie, explic);
               }
            break;
            case 'c': case 'C':
               System.out.println("Cuvant cautat:");
               linie = fluxIn.readLine();
               if( linie.length()>1) {
                  explic = dict.cautaCuvant(linie);
                  if (explic == null)
                     System.out.println("nu exista");
                  else
                     System.out.println("Explicatie:"+explic);
               }
            break;
            case 'l': case 'L':
               System.out.println("Afiseaza:");
               dict.afisDictionar();
            break;
         }
      } while(raspuns!='e' && raspuns!='E');
   }
}

6. Teme

Tema1. Dupa modelul prezentat in Activitatea in care s-a implementat structura Stiva, creati o clasa Coada care sa implementeze o structura de coada dupa principiul FIFO (first in, first out - primul venit, primul extras).

Tema2. Modificati exemplul "Interfete.java" care cuprinde ierarhia de Aparate electrice si electronice adaugand o clasa ColectieAparate derivata din LinkedList care sa permita operatii precum afiseaza colectie, porneste/opreste toate aparatele, respectiv opresteSeara, pornesteDimieata toate aparatele care permit asa ceva. La implementarea operatiilor, parcurgerea listei se va face prin iteratori.

Tema3 (optionala). Modificati exemplul Dictionar astfel incat sa permita salvarea, respectiv incarcarea intr-un fisier text al dictionarului prin metode specifice adaugate clasei.

© '2003 s.l. ing. Dan Pescaru - Universitatea "Politehnica" Timisoara