structuri de date în java (v)vega.unitbv.ro/~galmeanu/java/suport/curs-5/doc/java... ·...

33
1 Structuri de Date în Java (V) Hash codes Metoda hashCode () Cerinţele suprascrierii hashCode () Tipuri utilizator cu şi fără hashCode Folosirea colecţiilor Java Colecţii generice Iteratori Ştergerea obiectelor din colecţie Colecţiile List Colecţiile Set

Upload: others

Post on 30-Dec-2019

12 views

Category:

Documents


0 download

TRANSCRIPT

1

Structuri de Date în Java (V)

● Hash codes● Metoda hashCode ()● Cerinţele suprascrierii hashCode ()● Tipuri utilizator cu şi fără hashCode● Folosirea colecţiilor Java● Colecţii generice● Iteratori● Ştergerea obiectelor din colecţie● Colecţiile List● Colecţiile Set

2

Hash code

“O funcţie hash este orice procedură sau funcţie matematică riguros definită care converteşte un volum de date apreciabil, posibil de dimensiune variabilă, într-o dată de lungime mică, de obicei un simplu întreg. Valorile returnate de o funcţie hash sunt denumite hash codes.”

(Wikipedia)

3

Funcţiile hash “la lucru”

4

Ce este o valoare hash?

● O valoare întreagă care “se substituie” unui obiect

● Un mod rapid pentru a verifica inegalitatea a două obiecte

● Obiectele egale (ar trebui) să aibă valori hash egale

Q: De ce avem nevoie de ea?A: Pentru a distinge rapid între obiecte diferite

5

Metoda .hashCode()

public int hashCode ()

● Metodă a clasei Object, disponibilă a fi suprascrisă

● Definită în java.lang.Object să întoarcă o valoare aproape unică acelei instanţe

● Toate clasele o moştenesc iar unele o suprascriu

6

Cerinţele hashCode

● Valoarea hashCode a unui obiect nu se poate schimba dacă obiectul nu se modifică

● Două obiecte egale trebuie să aibă valori hashCode egale

● Este recomandabil ca două obiecte diferite să aibă valori hashCode distincte

7

Exemple hashCodeString radu = “Radu”;String radu2 = “Radu”;String diana = “Diana”;System.out.println (radu.hashCode());System.out.println (radu2.hashCode());System.out.println (diana.hashCode());// 1893428309, 1893428309, 7528268361

Integer int1 = 123456789;Integer int2 = 123456789;System.out.println (int1.hashCode());System.out.println (int2.hashCode());// 123456789, 123456789

8

Clasa Namepublic class Name {

public String first;public String last;

public Name (String first, String last) {this.first = first;this.last = last;

}public String toString () {

return first + " " + last;}public boolean equals (Object o) {

return (o instanceof Name && ((Name) o).first.equals (this.first) &&((Name) o).last.equals (this.last));

}}

9

Testarea funcţionării

Name radu = new Name ("Radu", "Ostrezu");Name dan = new Name ("Dan", "Apolosanu");Name dan2 = new Name ("Dan", "Apolosanu");

System.out.println (radu.equals (dan));System.out.println (dan.equals (dan2));System.out.println (radu.hashCode ());System.out.println (dan.hashCode ());System.out.println (dan2.hashCode ());// false, true, 17523401, 8567361, 9584176

● Obiectele sunt egale, hashCode-urile nu

10

Ce nevoie avem de hashCode?

● Clasa Name pare să funcţioneze

● Chiar e o problemă că n-am suprascris hashCode?

● Dacă nu folosim explicit hashCode, de ce ne-am obosi să o suprascriem?

11

JAVA foloseşte hashCode !

● Nu am respectat cerinţele hashCode!

● Avem două obiecte egale dar cu hashCode-uri diferite!

● Poate da naştere la comportamente ciudate şi imprevizibile

12

Comportament incorect

Set<String> strings = new HashSet<String> ();Set<Name> names = new HashSet<Name> (); strings.add ("Radu");names.add (new Name ("Dan", "Ostroveanu")); System.out.println (strings.contains ("Radu"));System.out.println (names.contains (

new Name ("Dan", "Ostroveanu")));

// true, false

13

Soluţia? Suprascrierea hashCode

Constrângeri:

● hashCode () trebuie să respecte egalitatea

● hashCode () trebuie să fie consistentă

● hashCode () trebuie să genereze int

● hashCode () ar fi bine să recunoască inegalitatea

14

O implementare posibilă

public class Name {// ...public int hashCode () {

return first.hashCode () + last.hashCode ();}

}

● Oare şi funcţionează?

15

Comportament corect, aşteptat

Set<Name> names = new HashSet<Name> (); names.add (new Name ("Dan", "Ostroveanu")); System.out.println (names.contains (

new Name ("Dan", "Ostroveanu")));

// true

● Se poate şi mai bine?

16

O implementare mai bună

public class Name {// ...public int hashCode () {

return first.hashCode () * 37 + last.hashCode ();

}}

● De ce este mai bună? (revedeţi cerinţele)

17

Cerinţele hashCode “reloaded”

● Valoarea hashCode a unui obiect nu se poate schimba dacă obiectul nu se modifică

● Două obiecte egale trebuie să aibă valori hashCode egale

● Este recomandabil ca două obiecte diferite să aibă valori hashCode distincte

● Exemplu: Dan Ostroveanu va fi diferit de Ostroveanu Dan

18

Înainte de a merge mai departe

● Aveţi nelămuriri în legătură cu hashCode? Întrebaţi acum!

● Vom folosi metoda ulterior în lucrul cu colecţii

● Vă poate cauza comportamente ciudate dacă nu-i înţelegeţi scopul

19

Colecţiile Java

● Sunt un ansambul de interfeţe şi clase ce realizează:

● Colectarea obiectelor laolaltă● Stocarea obiectelor● Sortarea obiectelor● Accesarea obiectelor

● Furnizează o sintaxă comună pentru toate variantele de implementare a colecţiilor

20

Cum folosim colecţiile

● Adăugăm import java.util.*; la începutul fişierului java unde folosim colecţia

package lab2;import java.util.*;public class CollectionUser {

List<String> list = new ArrayList<String> ();// ...

}

21

Sintaxa generală Collection<Ceva>

● boolean add (Ceva c);

● boolean contains (Object o);

● boolean remove (Ceva c);

● int size ();

Fiecare colecţie se particularizează pentru un tip de dată anume folosind '<' şi >' Spunem că folosim “şabloane”.

ex. Collection este o interfaţă şablon

22

Un exemplu de folosire

List<Name> unu = new ArrayList<Name> (); unu.add (new Name ("Dan", "Ostroveanu")); unu.add (new Name ("Radu", "Cuprescu")); System.out.println (unu.size()); unu.remove (new Name ("Dan", "Ostroveanu")); System.out.println (unu.size()); List<Name> doi = new ArrayList<Name> (); doi.add (new Name ("Mircea", "Kirakainen")); unu.addAll (doi); System.out.println (unu.size());

23

Colecţii generice

● Putem specifica tipul de dată pe care îl va folosi colecţia

● Ex: List<String> strings

● Suntem siguri că strings va conţine numai obiecte de tip String

● E opţional, însă foarte folositor

24

De ce folosim tipuri generice?

List untyped = new ArrayList ();List<String> typed = new ArrayList<String> ();

Object obj = untyped.get (0);String sillyString = (String) obj;String smartString = typed.get (0);

25

Accesarea obiectelor: iterator● Avem colecţia:

Collection<Ceva> col;● Iterator:

Iterator<Ceva> it = col.iterator ();while (it.hasNext ()) {

Ceva obj = it.next ();// procesăm obj

}● For each: // formă sinonimă, dar mai compactă

for (Ceva obj : col) {// procesăm obj

}

26

Ştergerea din colecţie a obiectelor

● Nu se pot scoate din colecţie obiectele în timp ce se iterează!for (Ceva obj : col) {

col.remove (obj); // ConcurrentModificatonException}

● Numai iteratorul poate şterge obiectul pe care iterează la acel moment

Iterator<Ceva> it = col.iterator ();while (it.hasNext ()) {

Ceva obj = it.next ();it.remove (obj); // şi nu col.remove (obj);

}● De remarcat că iter.remove este opţională şi nu toate obiectele ce implementează Iterator vor suporta metoda

27

Tipurile de colecţii generice

● List● ArrayList● LinkedList

● Set● HashSet● TreeSet

● Map● HashMap● TreeMap

28

Interfaţa List● Listă de obiecte accesabile într-o ordine, similară cu un

vector● Spre deosebire de vector, nu avem o mărime în care

trebuie să ne încadrăm● Ordinea elementelor din listă este dată de ordinea

introducerii lor

List<String> strings = new ArrayList<String> ();strings.add (“unu”); strings.add (“doi”);strings.add (“trei”);// strings = [ “unu”, “doi”, “trei” ]

29

Alte feluri de acces

● Introducerea cu un index:List<String> strings = new ArrayList<String> ();strings.add (“unu”);strings.add (“trei”);strings.add (1, “doi”);// strings = [ “unu”, “doi”, “trei” ]

● Accesarea obiectelor folosind un index:s.o.print (strings.get (0)); // “unu”s.o.print (strings.indexOf (“unu”)); // 0

30

Interfaţa Set

● Set-ul nu are nici size şi nici vreo ordine● Nu sunt permise obiecte duplicat!

Set<Name> names = new HashSet<Name> ();names.add (new Name (“Jack”, “Daniels”));names.add (new Name (“Jack”, “Daniels”));

System.out.println (names.size ()); // 1

31

Constrângerile folosirii Set-urilor

● Un obiect de tip Set nu poate fi modificat într-un fel care să-i afecteze testul de egalitate

● Toate metodele de modificare pot altera conţinutul, apelarea lor trebuie făcută selectiv

● Dacă nu respectaţi această constrângere, aşteptaţi-vă la comportamente bizare

32

Folosire incorectă

Set<Name> names = new HashSet<Name> ();Name jack = new Name (“Jack”, “Daniels”);names.add (jack);System.out.println (names.size ());

System.out.println (names.contains (jack)); // true

jack.last = "Rangers";

System.out.println (names.contains (jack)); // false System.out.println (names.size ()); // 1

33

Soluţii pentru rezolvare?

● Nu avem

● Aşa că nu se recomandă o astfel de abordare

● Dacă e posibil, folosiţi seturi de date ce nu se modifică

● Altfel, procedaţi cu atenţie