Linguaggi di Programmazione: Paradigmi di Programmazione Strutture Dati: Array & Co. Matteo Baldoni Dipartimento di Informatica - Universita` degli Studi di Torino C.so Svizzera, 185 - I-10149 Torino (Italy) e-mail: [email protected] - URL: http://www.di.unito.it/~baldoni Array • Gli array sono oggetti veri e propri (e quindi vanno prima creati esplicitamente dal programmatore per essere utilizzati) • Hanno una dimensione fissa (dopo la creazione) • Esistono solo unidimensionali (ma e` possibile definire array di array) • Il primo elemento ha indice “0” • La creazione avviene mediante l’operatore new Strutture Dati 2 1 Array • Es.: la dichiarazione di un array che puo` contenere 100 numeri interi • Gli elementi saranno indicizzati da 0 a 99 • Controllo a run time sul valore dell’indice tipo di un elemento dell’array int[] arrayOfInt = new int[100]; tipo array nome dell’array operatore che permette di creare un oggetto numero di elementi dell’array arrayOfInt[5] indice Strutture Dati 3 Array • Il nome dell’array e` un puntatore ad una struttura contenente i vari elementi • ma differenza del C/C++ il nome dell’array non indica anche il primo elemento dell’array stesso (non esiste un’aritmetica dei puntatori) • In Java non esistono analoghi di & e * del C/C++ int array_interi[]; int *array_interi; in C/C++ sono equivalenti array_interi[2] *(array_interi + 2) in C/C++ sono equivalenti Strutture Dati 4 2 Array • Se assegno un array ad un altro non copio gli elementi che esso contiene ma semplicemente il valore del puntatore, i due array condivideranno la stessa struttura (esiste pero` arraycopy nella classe System) • length (campo read-only) restituisce la lunghezza di un array arrayOfInt int[] arrayOfInt = new int[6]; […] int[] altroArrayOfInt; […] altroArrayOfInt altroArrayOfInt = arrayOfInt; […] System.out.println(arrayOfInt.length); stampa 6 5 Strutture Dati Inizializzazione di array • Mediante un loop (tipicamente un ciclo for) • oppure durante la definizione stessa • array anonimi come parametri attuali int[] arrayOfInt = new int[100]; for (int i=0; i<100; i++) arrayOfInt[i] = i; int[] arrayOfInt = {1, 2, 4, 10}; new int[] {1, 2, 4, 10} […] a.metodo(new int[] {1, 2, 4, 10}); […] Strutture Dati utile per array con pochi elementi utile per essere passato come parametro attuale di un metodo senza dover creare solo per questo una variabile 6 3 Array multidimensionali • Ossia array di array (ma non matrici!) • Ossia un elemento di un array puo` essere a sua volta un array int[][] arrayOfArrayOfInt = new int[10][5]; quadrato di elementi 10 x 5 int[][] arrayOfArrayOfInt = new int[10][]; for (int i=0; i<10; i++) arrayOfArrayOfInt[i] = new int[5]; int[][] arrayOfArrayOfInt = new int[10][]; for (int i=0; i<10; i++) arrayOfArrayOfInt[i] = new int[i]; triangolo di elementi 7 Strutture Dati Array • Gli array sono oggetti di “prima classe” • Gli array sono built-in nel linguaggio • L’operatore [] e`un costruttore di tipo! Definisce il tipo Counter public class Counter { private int c; […] } Counter[] arrayOfCounters = new Counter[10]; Definisce il tipo array di Counter Strutture Dati 8 4 Array class ProvaArray { public static void main(String[] args) { ClasseUno[] arrayClasseUno; ClasseDue[] arrayClasseDue; ClasseTre[] arrayClasseTre; ClasseDue[] arrayClasseDueBis; arrayClasseDue = new ClasseDue[] {new ClasseDue(2,3), new ClasseDue(3,4)}; arrayClasseUno = arrayClasseDue; arrayClasseDueBis = (ClasseDue[]) arrayClasseUno; arrayClasseTre = new ClasseTre[] {new ClasseTre("ab"), new ClasseTre("cd")}; arrayClasseUno = arrayClasseTre; ... } Upcast di tutti gli elementi Errore! Downcast di tutti gli elementi Strutture Dati 9 Array class ProvaArray { public static void main(String[] args) { ClasseUno[] arrayClasseUno; ClasseDue[] arrayClasseDue; ... arrayClasseDue = new ClasseDue[] {new ClasseDue(2,3), new ClasseDue(3,4)}; ... arrayClasseUno = arrayClasseDue; ... arrayClasseUno[0] = new ClasseUno(2); } Errore a run-time!! A tempo di compilazione è corretto assegnare ad un campo dell’array di tipo ClasseUno un elemento di tipo ClasseUno ma a run-time questo contiene un elemento di tipo ClasseDue, piu` specifico di ClasseUno, e quindi viene sollevata un’eccezione di tipo ArrayStoreException Strutture Dati 10 5 La classe java.util.Arrays • Mette a disposizione una serie di metodi statici di utilita` per trattare con array: – equals Fa uso di equals e non di == – fill Fa uso di compareTo – sort dell’interfaccia Comparable per parametrizzare l’algoritmo di – binarySearch ordinamento rispetto gli elementi Permette di usare anche oggetti di tipo Comparator (interfaccia) per parametrizzare rispetto al confronto • I metodi sono overloaded per ogni tipo primitivo e per Object. 11 Strutture Dati Strutture dati: Interfacce • Collection: un arbitraio gruppo di oggetti • List: un gruppo di oggetti memorizzati in una data sequenza • Set: un gruppo di oggetti senza duplicati • Map: un gruppo di coppie (oggetti) chiave-valore Strutture Dati Sono tutte interfacce! 12 6 Strutture dati: Implementazioni • Ogni interfaccia ha piu` implementazioni che possono essere scelte in modo indifferente a seconda delle esigenze (anche di efficienza) Strutture Dati 13 Strutture dati • Tassonomia completa delle strutture dati disponibili nel package java.util • Si noti Vector ancora consentito sebbene gli venga ora preferito ArrayList Strutture Dati 14 7 Strutture dati • Gli oggetti che possono essere contenuti in una qualsiasi struttura dati sono di tipo Object, quindi un oggetto qualsiasi • Un oggetto di tipo, ad esempio, ArrayList puo` contenere oggetti di tipo diverso, anche non omogenei (perche` comunque di tipo Object) • Viene persa l’informazione sul tipo di un oggetto quando è inserito in una struttura dati di questo genere (è come fare upcasting ad Object!) • Estratti gli oggetti è necessario fare downcasting per poterli riutilizzare correttamente (invocare metodi della loro classe di appartenenza), in contrapposizione agli array Strutture Dati 15 Un esempio • Tratto da: B. Eckel, Thinking in Java, Prentice Hall, 2000. Cap. 9, pag. 450 e seguenti. public class Cat { private int catNumber; Cat(int i) { catNumber = i; } void print() { System.out.println("Cat #" + catNumber); } } public class Dog { private int dogNumber; Dog(int i) { dogNumber = i; } void print() { System.out.println("Dog #" + dogNumber); } } Strutture Dati 16 8 Un esempio ArrayList non ha nessun riferimento a cosa conterra` in seguito! public class CatsAndDogs { public static void main(String[] args) { ArrayList cats = new ArrayList(); for(int i = 0; i < 7; i++) cats.add(new Cat(i)); Posso benissimo cats.add(new Dog(7)); aggiungere un for(int i = 0; i < cats.size(); i++) oggetto di tipo ((Cat)cats.get(i)).print(); Dog in cats! } Senza downcast non potrei invocarlo } import java.util.*; Durante la compilazione non viene rilevato nessun errore ma durante l’esecuzione (run-time) verra` sollevata un’eccezione (ClassCastException) poiche` verra` trovato un elemento non di tipo Cat (il downcast non è un cast alla C ma sono una verifica che l’oggetto sia effettivamente di un certo tipo) 17 Strutture Dati Un esempio public class Cat1 { private int catNumber; Cat(int i) { catNumber = i; } public String toString() { return "Cat #" + catNumber; } } A differenza di prima abbiamo un metodo toString() per stampare public class Dog1 { private int dogNumber; Dog(int i) { dogNumber = i; } public String toString() { return "Dog #" + dogNumber; } } Strutture Dati 18 9 Un esempio import java.util.*; public class CatsAndDogs { public static void main(String[] args) { Posso aggiungere ArrayList cats = new ArrayList(); un oggetto di tipo Dog for(int i = 0; i < 7; i++) cats.add(new Cat1(i)); Viene invocato cats.add(new Dog1(7)); implicitamente non è for(int i = 0; i < cats.size(); i++) necessario scriverlo //((Cat)cats.get(i)).print(); System.out.println(cats.get(i).toString()); } Durante la compilazione nessun errore poiche` } String toString() è un metodo disponibile in Object Non viene sollevata nessuna eccezione durante l’esecuzione!! Tutto funziona perfettamente. Questo perche` abbiamo fatto overriding di un metodo appartenente alla classe Object e quindi sopraclasse sia di Cat1 che di Dog1. Il binding dinamico associera` il corretto codice durante l’esecuzione Strutture Dati 19 Iteratori • È un oggetto che permette di attraversare agevolmente una struttura dati qualsiasi (indipendentemente dalla sua implementazione) • nest(), hasNext(), remove() import java.util.*; public class CatsAndDogs2 { public static void main(String[] args) { Collection cats = new ArrayList(); for(int i = 0; i < 7; i++) cats.add(new Cat(i)); Iterator e = cats.iterator(); while(e.hasNext()) ((Cat)e.next()).print(); } } Strutture Dati 20 10