12.07.2015 Views

Gestione di insiemi ed operazioni insiemistiche in Java tramite l ...

Gestione di insiemi ed operazioni insiemistiche in Java tramite l ...

Gestione di insiemi ed operazioni insiemistiche in Java tramite l ...

SHOW MORE
SHOW LESS
  • No tags were found...

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

4.2 Costruttori . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364.3 Implementazione dei meto<strong>di</strong> <strong>di</strong> LSet e LSetProtect<strong>ed</strong> . . . . 404.3.1 Meto<strong>di</strong> <strong>di</strong> tipo set e get . . . . . . . . . . . . . . . . . 404.3.2 Meto<strong>di</strong> <strong>di</strong> vario utilizzo . . . . . . . . . . . . . . . . . 404.3.3 Meto<strong>di</strong> <strong>di</strong> generazione <strong>di</strong> v<strong>in</strong>coli . . . . . . . . . . . . 425 Implementazione: la classe ConcreteMutableLSet 455.1 Costruttori . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465.2 Implementazione dei meto<strong>di</strong> <strong>di</strong> LSet e <strong>di</strong> LSetProtect<strong>ed</strong> . . 485.3 Implementazione dei meto<strong>di</strong> <strong>di</strong> java.util.Set . . . . . . . . 485.3.1 Inserimento e unione: add e addAll . . . . . . . . . . 505.3.2 Appartenenza e <strong>in</strong>clusione: conta<strong>in</strong>s e conta<strong>in</strong>sAll . 565.3.3 Estrazione e <strong>di</strong>fferenza: remove e removeAll . . . . . 605.3.4 Intersezione: reta<strong>in</strong>All . . . . . . . . . . . . . . . . . 645.3.5 Uguaglianza: equals . . . . . . . . . . . . . . . . . . . 685.3.6 iterator . . . . . . . . . . . . . . . . . . . . . . . . . 715.3.7 size . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745.3.8 isEmpty . . . . . . . . . . . . . . . . . . . . . . . . . . 755.3.9 clear . . . . . . . . . . . . . . . . . . . . . . . . . . . 766 Esempi 786.1 Utilizzo degli <strong><strong>in</strong>siemi</strong> <strong>di</strong> JSetL . . . . . . . . . . . . . . . . . . 786.1.1 La classe Color<strong>in</strong>g . . . . . . . . . . . . . . . . . . . . 786.1.2 Le mo<strong>di</strong>fiche a Color<strong>in</strong>g . . . . . . . . . . . . . . . . 806.2 Utilizzo degli <strong><strong>in</strong>siemi</strong> <strong>di</strong> java.util.Set . . . . . . . . . . . . 816.2.1 La classe Max . . . . . . . . . . . . . . . . . . . . . . . 816.3 Un esempio ibrido . . . . . . . . . . . . . . . . . . . . . . . . 827 Conclusioni e lavori futuri 852


Capitolo 1JSetL1.1 IntroduzioneJSetL [1, 2] è una libreria <strong>Java</strong> che offre alcune funzionalità per il supportoalla programmazione <strong>di</strong>chiarativa. Questo para<strong>di</strong>gma <strong>di</strong> programmazioneconsiste nello specificare che cosa il programma deve fare, piuttosto checome farlo, tipico <strong>in</strong>vece della programmazione imperativa. La soluzioneviene qu<strong>in</strong><strong>di</strong> trovata attraverso un <strong>in</strong>sieme <strong>di</strong> con<strong>di</strong>zioni e <strong>di</strong> v<strong>in</strong>coli e noncon una lista <strong>di</strong> istruzioni da seguire <strong>in</strong> or<strong>di</strong>ne specifico.In particolare JSetL fornisce funzionalità tipiche della:• programmazione logica a v<strong>in</strong>coli (CLP [4]) tra cui: unificazione, variabililogiche, strutture dati ricorsive, soluzione <strong>di</strong> v<strong>in</strong>coli, non determ<strong>in</strong>ismo;• programmazione logica a v<strong>in</strong>coli con <strong><strong>in</strong>siemi</strong> (ad esempio CLP(SET )[5]),tra cui la possibilità <strong>di</strong> creare <strong><strong>in</strong>siemi</strong> anche specificati parzialmente e<strong>di</strong> operare su essi attraverso v<strong>in</strong>coli.Nei l<strong>in</strong>guaggi logici il programma è costituito da una sequenza <strong>di</strong> asserzioni(fatti) e regole; l’esecuzione del programma consiste nella <strong>di</strong>mostrazion<strong>ed</strong>ella verità <strong>di</strong> una formula <strong>di</strong> partenza (il goal). Nella ricerca <strong>di</strong> tale <strong>di</strong>mostrazioneassumono importanza meccanismi quali il pattern match<strong>in</strong>g (<strong>in</strong>3


italiano potremo tradurre <strong>in</strong> “combaciamento <strong>di</strong> forme”) e il backtrack<strong>in</strong>g(se il sistema durante la ricerca entra <strong>in</strong> un vicolo cieco, ritorna alla sceltafatta più recentemente e prova ad applicare la regola o il fatto seguente).I pr<strong>in</strong>cipali vantaggi della programmazione <strong>di</strong>chiarativa sono: la facilità<strong>di</strong> sviluppo del programma, la comprensibilità, la riusabilità, la concisionee il parallelismo implicito.1.2 Caratteristiche pr<strong>in</strong>cipali <strong>di</strong> JSetLVe<strong>di</strong>amo brevemente quali sono le pr<strong>in</strong>cipali caratteristiche della libreriaJSetL:• Variabili logiche: hanno lo stesso significato che possi<strong>ed</strong>ono nei l<strong>in</strong>guaggi<strong>di</strong> programmazione logica e funzionale. Possono essere <strong>in</strong>izializzateo non <strong>in</strong>izializzate, il loro valore può essere <strong>di</strong> ogni tipo e puòessere determ<strong>in</strong>ato come risultato <strong>di</strong> v<strong>in</strong>coli che co<strong>in</strong>volgono le variabilistesse.• Liste e <strong><strong>in</strong>siemi</strong>: sono strutture dati la cui pr<strong>in</strong>cipale <strong>di</strong>fferenza consistenel fatto che nelle liste è importante l’or<strong>di</strong>ne e la ripetizion<strong>ed</strong>egli elementi, mentre negli <strong><strong>in</strong>siemi</strong> l’or<strong>di</strong>ne e la ripetizione non hannoimportanza. Entrambe le strutture dati possono essere parzialmentespecificate, cioè possono contenere variabili logiche non <strong>in</strong>izializzatesia come elementi che come parte della struttura dati.• Unificazione: l’unificazione tra due oggetti può essere usata pertestare l’equivalenza tra essi o per assegnare valori alle variabili logichenon <strong>in</strong>izializzate <strong>in</strong> essi eventualmente contenute.• V<strong>in</strong>coli: uguaglianza, <strong>di</strong>suguaglianza <strong>ed</strong> <strong>operazioni</strong> <strong><strong>in</strong>siemi</strong>stiche <strong>di</strong>base, come <strong>di</strong>fferenza, unione, <strong>in</strong>tersezione, sono trattati come v<strong>in</strong>coli<strong>in</strong> JSetL. I v<strong>in</strong>coli vengono <strong>in</strong> primo luogo aggiunti al constra<strong>in</strong>t storee poi risolti <strong>tramite</strong> il constra<strong>in</strong>t solver.4


• Non determ<strong>in</strong>ismo: i v<strong>in</strong>coli <strong>in</strong> JSetL vengono risolti <strong>in</strong> manieranon determ<strong>in</strong>istica, sia perché l’or<strong>di</strong>ne <strong>in</strong> cui sono risolti non è importante,sia perché nella loro risoluzione si utilizzano i punti <strong>di</strong> scelta eil backtrack<strong>in</strong>g.• V<strong>in</strong>coli def<strong>in</strong>iti dall’utente: attraverso la classe NewConstra<strong>in</strong>tsJSetL permette all’utente <strong>di</strong> def<strong>in</strong>ire nuovi v<strong>in</strong>coli.1.3 Def<strong>in</strong>izione e uso <strong>di</strong> variabili logiche e <strong><strong>in</strong>siemi</strong>Variabili logicheDef<strong>in</strong>izione 1.3.1 Una variabile logica è un’istanza della classe Lvar,creata dalla <strong>di</strong>chiarazioneLvar nomeVar = new Lvar(NomeVarExt, ValoreVar);dove nomeVar è il nome della variabile, NomeVarExt è un nome esterno(parametro opzionale), ValoreVar è un valore (anch’esso opzionale) <strong>di</strong> <strong>in</strong>izializzazion<strong>ed</strong>ella variabile stessa.Def<strong>in</strong>izione 1.3.2 Una variabile logica che non ha un valore associato conessa è detta non <strong>in</strong>izializzata (o <strong>in</strong>cognita). Altrimenti la variabile è detta<strong>in</strong>izializzata.Il valore <strong>di</strong> una variabile logica può essere specificato o quando la variabileè creata o come il risultato <strong>di</strong> elaborazione <strong>di</strong> v<strong>in</strong>coli che la co<strong>in</strong>volgono,<strong>in</strong> particolare, v<strong>in</strong>coli <strong>di</strong> uguaglianza.Oltre ai v<strong>in</strong>coli, la classe Lvar fornisce meto<strong>di</strong> che permettono <strong>di</strong> leggere escrivere il valore della variabile logica, <strong>di</strong> conoscere se la variabile è <strong>in</strong>izializzatao no, <strong>di</strong> ottenere il suo nome esterno, e cosi via.InsiemiDef<strong>in</strong>izione 1.3.3 Un <strong>in</strong>sieme è una collezione f<strong>in</strong>ita <strong>di</strong> valori (elementidell’<strong>in</strong>sieme). In JSetL un <strong>in</strong>sieme è un’istanza della classe Set, creata dalla<strong>di</strong>chiarazione5


Set nomeSet = new Set(NomeSetExt, ValoreSetElem);dove nomeSet è il nome dell’<strong>in</strong>sieme, NomeSetExt è un nome esterno (paramentroopzionale), ValoreSetElem è una parte opzionale che è usata perspecificare gli elementi dell’<strong>in</strong>sieme e può essere un array <strong>di</strong> elementi c 1 , . . . , c n<strong>di</strong> un qualsiasi tipo, o i limiti l e u <strong>di</strong> un <strong>in</strong>tervallo [l,u] <strong>di</strong> numeri <strong>in</strong>teri.L’<strong>in</strong>sieme vuoto è denotato dalla costante Set.empty.Gli <strong><strong>in</strong>siemi</strong> possono essere <strong>in</strong>izializzati o non <strong>in</strong>izializzati e gli elementipossono essere <strong>di</strong> qualsiasi tipo. Il valore <strong>di</strong> un <strong>in</strong>sieme può essere specificatoelencando i suoi elementi <strong>in</strong> un array o, implicitamente, fornendo i limiti <strong>di</strong>un <strong>in</strong>tervallo <strong>di</strong> numeri <strong>in</strong>teri, o attraverso un altro <strong>in</strong>sieme.Esempi <strong>di</strong> utilizzo <strong>di</strong> Lvar e SetEsempio 1.3.1 Dichiarazioni <strong>di</strong> oggetti <strong>di</strong> Lvar e Set.Lvar x = new Lvar();//variabile logica non <strong>in</strong>izializzataLvar y = new Lvar( ′′ y ′′ ,‘a’); //var. l. <strong>in</strong>izializzata//con nome esterno “y” e valore ‘a’Lvar t = new Lvar(x); //var. l. non <strong>in</strong>izializzata (come x)Set z = new Set( ′′ z ′′ );//<strong>in</strong>sieme non <strong>in</strong>izializzato con nome esterno “z”Set i = new Set(4,4+3); //<strong>in</strong>sieme <strong>in</strong>izializzato con valore {4,5,6,7}<strong>in</strong>t[] s elems = {2,4,8,3};Set s = new Set( ′′ s ′′ ,s elems); //<strong>in</strong>sieme <strong>in</strong>izializzato con nome//esterno “s” e valore {2,4,8,3}Lvar r = new Lvar(new Set()); //var. l. non <strong>in</strong>izializzata, il cui valore è//un <strong>in</strong>sieme non <strong>in</strong>izializzatoDef<strong>in</strong>izione 1.3.4 Un <strong>in</strong>sieme che contiene alcuni elementi che non sono<strong>in</strong>izializzati è detto <strong>in</strong>sieme parzialmente specificato.Def<strong>in</strong>izione 1.3.5 Gli elementi <strong>di</strong> un <strong>in</strong>sieme che sono essi stessi <strong><strong>in</strong>siemi</strong>sono detti <strong><strong>in</strong>siemi</strong> annidati.Esempio 1.3.2 Insiemi parzialmente specificati e annidati.6


Lvar x = new Lvar();Object[] pl elems = {new Integer(1),x};Set ps = new Set(pl elems);Set[] ns elems = {i,s,r};Set ns = new Set(ns elems);//l’<strong>in</strong>sieme {1,x}//i, s e r sono <strong><strong>in</strong>siemi</strong>//def<strong>in</strong>iti nell’esempio 1.3.1//l’<strong>in</strong>sieme {{4,5,6,7},{2,3,8,3},r}Def<strong>in</strong>izione 1.3.6 Un <strong>in</strong>sieme è detto illimitato se contiene un certo numero<strong>di</strong> elementi (noti o meno) e 1 , . . . , e n e un “resto” r, rappresentato daun <strong>in</strong>sieme non <strong>in</strong>izializzato. La notazione usata è la seguente:{e 1 , . . . , e n |r}Un <strong>in</strong>sieme illimitato viene costruito <strong>tramite</strong> i meto<strong>di</strong> <strong>di</strong> <strong>in</strong>serimento <strong>in</strong>s e<strong>in</strong>sAll. Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo <strong>di</strong> questi meto<strong>di</strong>:Esempio 1.3.3 Insiemi completamente specificati, parzialmente specificatie illimitati.Set s1 = Set.empty.<strong>in</strong>s(1); // l’<strong>in</strong>sieme {1}Lvar x = new Lvar();Set s2 = s1.<strong>in</strong>s(3).<strong>in</strong>s(x);// <strong>in</strong>sieme parzialm. specif. {3,1,x}<strong>in</strong>t[] s3 elems = {1,2,3};Set s3 = Set.empty.<strong>in</strong>sAll(s3 elems); //<strong>in</strong>sieme completam. specif. {1,2,3}Set r = new Set( ′′ r ′′ );//<strong>in</strong>sieme non <strong>in</strong>izializzato, r = unknownSet us = r.<strong>in</strong>s(1);//<strong>in</strong>sieme illimitato {1|r}1.4 I v<strong>in</strong>coli <strong>in</strong> JSetLJSetL fornisce dei v<strong>in</strong>coli per specificare con<strong>di</strong>zioni su variabili logiche e <strong><strong>in</strong>siemi</strong>.I v<strong>in</strong>coli attivi <strong>di</strong> un programma vengono memorizzati nel constra<strong>in</strong>tstore del constra<strong>in</strong>t solver S, un’istanza della classe SolverClass. JSetLfornisce i meto<strong>di</strong> attraverso i quali è possibile aggiungere nuovi v<strong>in</strong>coli al7


constra<strong>in</strong>t store, visualizzarne il contenuto e rimuovere tutti i v<strong>in</strong>coli presenti.L’<strong>in</strong>troduzione <strong>di</strong> un nuovo v<strong>in</strong>colo avviene attraverso il metodo adddella classe SolverClass:S.add(C);che aggiunge il v<strong>in</strong>colo C al constra<strong>in</strong>t store <strong>di</strong> S. Quando tutti i v<strong>in</strong>coli sonostati aggiunti al constra<strong>in</strong>t store, possiamo risolverli <strong>in</strong>vocando il metodosolve (o boolSolve) della classe SolverClass:S.solve();Questo metodo ricerca, <strong>in</strong> modo non-determ<strong>in</strong>istico, una soluzione che sod<strong>di</strong>sfitutti i v<strong>in</strong>coli <strong>in</strong>trodotti. Se non esiste alcuna soluzione, viene generataun’eccezione Failure e la computazione term<strong>in</strong>a. Il metodo solve tienetraccia delle alternative rimaste <strong>in</strong>esplorate durante la ricerca e <strong>in</strong> caso <strong>di</strong>backtrack<strong>in</strong>g torna ad un punto <strong>di</strong> scelta prec<strong>ed</strong>ente che abbia ancora dellealternative aperte e cont<strong>in</strong>ua la ricerca da quel punto f<strong>in</strong>o a trovare, se esiste,una soluzione. Il metodo boolSolve si comporta <strong>in</strong> modo analogo, maritorna true se il v<strong>in</strong>colo è stato risolto con successo e false se il risolutore<strong>di</strong> v<strong>in</strong>coli non ha trovato nessuna soluzione (a <strong>di</strong>fferenza del metodo solvenon lancia un’eccezione).1.5 Un esempio <strong>di</strong> JSetLVe<strong>di</strong>amo ora un esempio <strong>di</strong> utilizzo della libreria JSetL <strong>in</strong> cui si usano <strong>in</strong>particolare <strong><strong>in</strong>siemi</strong> e variabili logiche. L’obiettivo del seguente programma è<strong>di</strong> trovare, <strong>in</strong> un <strong>in</strong>sieme <strong>di</strong> <strong>in</strong>teri, quello che ha valore massimo. La soluzioneviene trovata <strong>in</strong> modo <strong>di</strong>chiarativo, ovvero un elemento x <strong>di</strong> s è il massimo<strong>di</strong> s se per ogni elemento y <strong>di</strong> s si ha y x.class Max {static SolverClass Solver = new SolverClass();public static Lvar max(Set s) throws Failure {8


}Lvar x = new Lvar();Lvar y = new Lvar();Solver.add(x.<strong>in</strong>(s));Solver.forall(y, s, y.le(x));Solver.solve();return x;}public static void ma<strong>in</strong> (Str<strong>in</strong>g[] args) throws Failure {<strong>in</strong>t[] a = {1,6,4,8,10,5};Set s = new Set(a); // S = {1,6,4,8,10,5}System.out.pr<strong>in</strong>t("Max = ");max(s).pr<strong>in</strong>t();}La prima <strong>di</strong>chiarazione nella classe Max crea un oggetto della classeSolverClass, chiamato Solver. Il metodo max prende un Set s comeparametro e def<strong>in</strong>isce due variabili logiche x e y non <strong>in</strong>izializzate. L’oggettoSolver <strong>in</strong>voca il metodo add che aggiunge il v<strong>in</strong>colo x.<strong>in</strong>(s) (x ∈ s)all’attuale constra<strong>in</strong>t store. Il v<strong>in</strong>colo restituisce true se s è un <strong>in</strong>sieme ex appartiene ad s. Se x è non <strong>in</strong>izializzato quando l’espressione è valutataquesto equivale ad assegnare <strong>in</strong> modo non determ<strong>in</strong>istico un elemento <strong>di</strong> sad x. L’<strong>in</strong>vocazione del metodo forall ci permette <strong>di</strong> aggiungere al constra<strong>in</strong>tstore il nuovo v<strong>in</strong>colo y.le(x) (y x) per ogni y appartenente as. Non appena il metodo solve è <strong>in</strong>vocato, il constra<strong>in</strong>t solver controlla sel’attuale collezione <strong>di</strong> v<strong>in</strong>coli nel constra<strong>in</strong>t store è sod<strong>di</strong>sfacente o no. Selo è, l’<strong>in</strong>vocazione del metodo solve term<strong>in</strong>a restituendo il risultato <strong>di</strong> max.Se, al contrario, uno dei v<strong>in</strong>coli nel constra<strong>in</strong>t store è valutato false, si hail backtrack<strong>in</strong>g e il calcolo torna <strong>in</strong><strong>di</strong>etro al punto <strong>di</strong> scelta più vic<strong>in</strong>o. Inquesto caso il più vic<strong>in</strong>o e l’unico punto <strong>di</strong> scelta è quello creato dal v<strong>in</strong>colox.<strong>in</strong>(s). La sua esecuzione legherà <strong>in</strong> modo non determ<strong>in</strong>istico x con ogni9


elemento <strong>di</strong> s, uno dopo l’altro. Se tutti i valori <strong>di</strong> s sono stati confrontati,il calcolo <strong>di</strong> max term<strong>in</strong>a sollevando l’eccezione Failure. Se l’eccezione nonè catturata con un’istruzione catch, l’<strong>in</strong>tero programma term<strong>in</strong>a segnalandoun fallimento. Eseguendo il programma con il semplice <strong>in</strong>sieme <strong>di</strong> <strong>in</strong>teri<strong>di</strong>chiarati nel metodo ma<strong>in</strong> si ha il risultato Max = 10.10


Capitolo 2L’<strong>in</strong>terfaccia Set <strong>di</strong> <strong>Java</strong>In questo capitolo illustriamo le caratteristiche pr<strong>in</strong>cipali della classe Set <strong>di</strong><strong>Java</strong> e del contesto <strong>in</strong> cui essa si <strong>in</strong>serisce. Prima <strong>di</strong> questo però è opportunov<strong>ed</strong>ere brevemente come funziona l’ere<strong>di</strong>tarietà <strong>in</strong> <strong>Java</strong> e cosa sono le classiconcrete, le classi astratte e le <strong>in</strong>terfacce.2.1 Ere<strong>di</strong>tarietà, classi concrete, classi astratte e<strong>in</strong>terfacce <strong>in</strong> <strong>Java</strong>Classi concreteUna classe è un raggruppamento <strong>di</strong> dati (variabili membro) e <strong>di</strong> funzioni(meto<strong>di</strong>) che operano su questi dati. La def<strong>in</strong>izione <strong>di</strong> classe <strong>in</strong> <strong>Java</strong> sirealizza nella seguente forma:[public] class NomeClasse {// def<strong>in</strong>izioni <strong>di</strong> variabili membro// costruttori// def<strong>in</strong>izioni <strong>di</strong> meto<strong>di</strong>}dove la parola public è opzionale: se la si omette, <strong>di</strong> default la classe saràvisibile solo dalle altre classi del package, altrimenti sarà accessibile da qual-11


siasi altra classe. Una classe concreta non contiene meto<strong>di</strong> abstract (sezione2.1) e può essere usata per istanziare oggetti. Un oggetto è un esemplareconcreto <strong>di</strong> una classe. In <strong>Java</strong> esso viene creato attraverso l’operatore newseguito da un costruttore della classe. Ad esempio, le istruzioniNomeClasse oggetto1 = new NomeClasse();NomeClasse oggetto2 = new NomeClasse(arg1);NomeClasse oggetto3 = new NomeClasse(arg1, arg2);creano tre oggetti <strong>di</strong> classe NomeClasse. Nel primo caso viene richiamato uncostruttore senza parametri della classe NomeClasse che normalmente creaun oggetto i cui campi dato hanno un valore <strong>in</strong>def<strong>in</strong>ito, negli altri due casil’oggetto viene costruito con determ<strong>in</strong>ati valori. Per richiamare un metododella classe si utilizza l’operatore ‘.’ applicato ad un oggetto della classe(oggetto <strong>di</strong> <strong>in</strong>vocazione). Ad esempio:oggetto1.nomeFunzione();richiama il metodo <strong>di</strong> nome nomeFunzione, senza parametri, sull’oggettooggetto1. Ve<strong>di</strong>amo un esempio più concreto:// Def<strong>in</strong>izione della classe Apublic class A {private <strong>in</strong>t a; //variabilepublic A() {a = 0;} //costruttore senza parametripublic A(<strong>in</strong>t x) {a = x;} //costruttore con un parametropublic <strong>in</strong>t getA() {return a;} //metodo}// Creazione <strong>di</strong> due oggetti <strong>di</strong> tipo AA ogg1 = new A(); //la variabile ‘a’ vale 0A ogg2 = new A(3); //la variabile ‘a’ vale 3// Chiamata del metodo getA() dall’oggetto ogg212


<strong>in</strong>t y = ogg2.getA(); // <strong>in</strong> y viene memorizzato il valore <strong>di</strong> a,// che <strong>in</strong> questo caso è 3Ere<strong>di</strong>tarietàL’ere<strong>di</strong>tarietà è una forma <strong>di</strong> riutilizzo del software, <strong>in</strong> quanto le nuove classivengono create “assorbendo” gli attributi e i meto<strong>di</strong> <strong>di</strong> una classe esistente,e sovrascrivendo e migliorando le caratteristiche <strong>di</strong> quest’ultima <strong>in</strong> base allenuove necessità. Quando si def<strong>in</strong>isce una nuova classe, anziché <strong>di</strong>chiarareper esteso meto<strong>di</strong> e variabili membro completamente nuovi, si può decidereche la nuova classe ere<strong>di</strong>ti i membri <strong>di</strong> una classe (che prende il nome <strong>di</strong>superclasse) già def<strong>in</strong>ita. La nuova classe prende il nome <strong>di</strong> sottoclasse. Unasottoclasse (che può a sua volta <strong>di</strong>ventare una superclasse <strong>di</strong> una classe futura),aggiunge normalmente i propri meto<strong>di</strong> e variabili <strong>di</strong> istanza a quelliere<strong>di</strong>tati dalla superclasse; qu<strong>in</strong><strong>di</strong>, una sottoclasse è più specifica rispettoalla sua superclasse e rappresenta un <strong>in</strong>sieme <strong>di</strong> oggetti più piccolo. Tipicamente,la sottoclasse ha i comportamenti della sua superclasse, ma aggiungecomportamenti specifici.La superclasse <strong>di</strong>retta è la superclasse da cui la sottoclasse ere<strong>di</strong>ta <strong>in</strong> modoesplicito. In <strong>Java</strong> l’ere<strong>di</strong>tarietà (<strong>di</strong>retta) viene espressa nel seguente modo:[public] class NomeSottoclasse extends NomeSuperclasse {}// corpo della classeUna superclasse <strong>in</strong><strong>di</strong>retta è <strong>in</strong>vece ere<strong>di</strong>tata da due o più livelli superioridella gerarchia delle classi, che def<strong>in</strong>isce le relazioni <strong>di</strong> ere<strong>di</strong>tarietà trale classi. In <strong>Java</strong>, la gerarchia delle classi <strong>in</strong>izia con la classe Object (nelpackage java.lang), da cui ogni classe <strong>Java</strong>, <strong>di</strong>rettamente o <strong>in</strong><strong>di</strong>rettamente,ere<strong>di</strong>ta.Nell’ere<strong>di</strong>tarietà s<strong>in</strong>gola, una nuova classe può essere derivata da una solasottoclasse. A <strong>di</strong>fferenza del l<strong>in</strong>guaggio C++, <strong>Java</strong> non supporta l’ere<strong>di</strong>tarietàmultipla (<strong>in</strong> cui una classe viene derivata da più superclassi <strong>di</strong>rette), ma13


supporta la nozione <strong>di</strong> <strong>in</strong>terfaccia, che v<strong>ed</strong>remo tra poco. Le <strong>in</strong>terfacce aiutano<strong>Java</strong> a sfruttare molti dei vantaggi dell’ere<strong>di</strong>tarietà multipla. Ve<strong>di</strong>amopiù <strong>in</strong> concreto come funziona l’ere<strong>di</strong>tarietà <strong>in</strong> <strong>Java</strong> con un esempio <strong>in</strong> cuiuna classe Studente è def<strong>in</strong>ita <strong>tramite</strong> l’ere<strong>di</strong>tarietà <strong>di</strong>retta da una classePersona:public class Persona {private Str<strong>in</strong>g nome;private Str<strong>in</strong>g cognome;public Persona() {...}public Persona(Str<strong>in</strong>g n, Str<strong>in</strong>g c) {...}public setNome(Str<strong>in</strong>g n) {...}public getNome() {...}...}public class CurriculumUniversitario {...}public class Studente extends Persona {// Ere<strong>di</strong>ta le variabili membro e i meto<strong>di</strong> della classe Persona.// Aggiunge caratteristiche specifiche della classe Studente:private <strong>in</strong>t matricola;private CurriculumUnivesitario cu;public setMatricola(<strong>in</strong>t m) {...}public getMatricola() {...}...}È importante saper <strong>di</strong>st<strong>in</strong>guere la relazione “è un” dalla relazione “haun”. “È un” rappresenta l’ere<strong>di</strong>tarietà, ovvero un oggetto <strong>di</strong> una sottoclassepuò essere trattato anche come un oggetto della superclasse. Peresempio, “uno Studente è una Persona”. Invece, la relazione “ha un”14


identifica la composizione, cioè un oggetto <strong>di</strong> una classe ha come membriuno o più oggetti <strong>di</strong> altre classi. Per esempio, “uno studente `ha unCurriculumUniversitario”.Classi astratteIn <strong>Java</strong> una classe astratta viene <strong>di</strong>chiarata tale premettendo la parola chiaveabstract alla <strong>di</strong>chiarazione della classe. La caratteristica pr<strong>in</strong>cipale <strong>di</strong> unaclasse astratta è che da essa non è possibile creare un’istanza, a <strong>di</strong>fferenzadelle classi concrete. Una classe astratta ha dei meto<strong>di</strong> astratti (anch’essiprec<strong>ed</strong>uti dalla parola abstract), cioè dei meto<strong>di</strong> che non hanno implementazione;<strong>in</strong> tal modo si obbliga le classi derivate a fornire un’implementazioneadeguata del metodo. Se una classe ha anche solo un metodo abstract èobbligatorio che la classe sia abstract. In ogni sottoclasse questo metododovrà essere ridef<strong>in</strong>ito o dovrà essere a sua volta <strong>di</strong>chiarato come abstract(il metodo e la sottoclasse). Una classe abstract può avere meto<strong>di</strong> che nonsono astratti. Anche se non si possono creare oggetti <strong>di</strong> questa classe, lesue sottoclassi ere<strong>di</strong>teranno il metodo pronto per essere utilizzato. La formas<strong>in</strong>tattica generale <strong>di</strong> una classe astratta <strong>in</strong> <strong>Java</strong> è la seguente:[public] abstract class NomeClasse {// meto<strong>di</strong> astrattiabstract tipoDiRitorno1 metodo1(arg1);...abstract tipoDiRitornoN metodoM(argN);// [meto<strong>di</strong> non astratti][tipoDiRitorno1 metodo1(arg1) {//corpo del metodo}...tipoDiRitornoM metodoM(argM) {//corpo del metodo}]}Dato che i meto<strong>di</strong> static non possono essere ridef<strong>in</strong>iti, un metodo a-stratto non può essere statico.15


Ve<strong>di</strong>amo un esempio più concreto:public abstract class A {public abstract <strong>in</strong>t f();public abstract <strong>in</strong>t g(<strong>in</strong>t x);public void h() {...}...}public class B extends A {<strong>in</strong>t f() {...} //implementazione del metodo f<strong>in</strong>t g(<strong>in</strong>t x) {...} //implementazione del metodo g// resto della classe...}Nell’esempio la classe B estende A implementando i suoi meto<strong>di</strong> astratti: <strong>in</strong>questo modo è possibile creare un’istanza <strong>di</strong> B.InterfacceUn’<strong>in</strong>terfaccia è un <strong>in</strong>sieme <strong>di</strong> <strong>di</strong>chiarazioni <strong>di</strong> meto<strong>di</strong> senza la def<strong>in</strong>izione,ovvero senza il corpo che ne specifica l’implementazione. Questi meto<strong>di</strong>def<strong>in</strong>iscono un tipo <strong>di</strong> comportamento; tutte le classi che implementano unadeterm<strong>in</strong>ata <strong>in</strong>terfaccia sono obbligate a dare una def<strong>in</strong>izione dei meto<strong>di</strong>dell’<strong>in</strong>terfaccia e <strong>in</strong> questo senso acquistano un comportamento o un modo<strong>di</strong> funzionamento.In <strong>Java</strong> la <strong>di</strong>chiarazione <strong>di</strong> un’<strong>in</strong>terfaccia è del tutto analoga a quella<strong>di</strong> una classe, basta sostituire la parola class con la parola <strong>in</strong>terface; las<strong>in</strong>tassi è la seguente:[public] <strong>in</strong>terface NomeInterfaccia[extends Interfaccia1,...,InterfacciaN] {[static f<strong>in</strong>al tipo1 var1 = valore1;16


}...static f<strong>in</strong>al tipoN varN = valoreN;]tipoDiRitorno1 metodo1(arg1);...tipoDiRitornoM metodoM(argM);Come si può v<strong>ed</strong>ere un’<strong>in</strong>terfaccia specifica solo meto<strong>di</strong> che devono essereimplementati; <strong>in</strong> <strong>Java</strong> tutte le <strong>in</strong>terfacce sono pubbliche e tutti i suoi meto<strong>di</strong>sono implicitamente pubblici <strong>ed</strong> astratti. Sono anche permessi attributipublic static f<strong>in</strong>al (le costanti), che devono essere necessariamente <strong>in</strong>izializzate,perché le variabili dell’<strong>in</strong>terfaccia non possono essere mo<strong>di</strong>ficate.Un’<strong>in</strong>terfaccia può estendere i meto<strong>di</strong> <strong>di</strong> un’altra <strong>in</strong>terfaccia, esattamentecome accade per le classi.Una classe può implementare una o più <strong>in</strong>terfacce <strong>di</strong>chiarandole esplicitamentee implementando i meto<strong>di</strong> <strong>di</strong>chiarati nelle <strong>in</strong>terfacce stesse. In talcaso, gli oggetti <strong>di</strong> questa classe saranno riconosciuti anche come oggetti cheimplementano l’<strong>in</strong>terfaccia. La <strong>di</strong>chiarazione <strong>di</strong> implementazione all’<strong>in</strong>terno<strong>di</strong> una classe si ottiene per mezzo della parola chiave implements seguitadal nome <strong>di</strong> una o più <strong>in</strong>terfacce separate da virgole:class NomeClasse implements Interfacccia1,...,InterfacciaN {//implementazione dei meto<strong>di</strong> delle <strong>in</strong>terfacce//più eventuali altri meto<strong>di</strong> specifici}Ad esempio:public <strong>in</strong>terface I1 {public void f();}public <strong>in</strong>terface I2 {public <strong>in</strong>t g();17


}public class C implements I1,I2 {public void f() {...} //implementazione metodo <strong>di</strong> I1public <strong>in</strong>t g() {...} //implementazione metodo <strong>di</strong> I2public str<strong>in</strong>g s() {...} //implementazione metodo proprio <strong>di</strong> C}Ovviamente però non si può creare un’istanza <strong>di</strong> un’<strong>in</strong>terfaccia con l’istruzionenew, per cui quando un oggetto è <strong>di</strong> tipo corrispondente a un’<strong>in</strong>terfacciasignifica che appartiene a una classe che implementa quell’<strong>in</strong>terfaccia. Adesempio:// Creazione <strong>di</strong> un oggetto <strong>di</strong> tipo <strong>in</strong>terfaccia (1);I x1 = new C();x1.f(); // okx1.g(); // errore! Dentro a I non esiste g()// Creazione <strong>di</strong> un oggetto <strong>di</strong> tipo classe concreta (2):C x2 = new C();x2.f(); // okx2.g(); // okÈ importante capire che quando un oggetto è <strong>di</strong> tipo corrispondentea un’<strong>in</strong>terfaccia, si possono utilizzare solo i meto<strong>di</strong> dell’<strong>in</strong>terfaccia e noneventuali meto<strong>di</strong> aggiunti nella classe concreta; per poterli utilizzare tuttibisogna creare l’oggetto come nell’esempio (2).Una classe può avere solo una superclasse, mentre può implementare unqualsiasi numero <strong>di</strong> <strong>in</strong>terfacce. In questo modo <strong>in</strong> <strong>Java</strong> viene supportatal’ere<strong>di</strong>tarietà multipla. Ve<strong>di</strong>amo un esempio:public <strong>in</strong>terface I1 {public static f<strong>in</strong>al <strong>in</strong>t a = 10;public <strong>in</strong>t f(double x);18


}public void g();...public <strong>in</strong>terface I2 {}public <strong>in</strong>t p();public <strong>in</strong>terface I3 extends I1 {public Str<strong>in</strong>g h(Str<strong>in</strong>g s);...}public class C1 {...}public class C2 extends C1 implements I2, I3 {public <strong>in</strong>t p() {...}public <strong>in</strong>t f(double x) {...}public void g() {...}public Str<strong>in</strong>g h(Str<strong>in</strong>g s) {...}// Resto della classe...}In questo esempio la classe C2 ere<strong>di</strong>ta i membri e i meto<strong>di</strong> <strong>di</strong> C1 e fornisceun’implementazione <strong>di</strong> tutti meto<strong>di</strong> delle <strong>in</strong>terfacce I2 e I3 e anch<strong>ed</strong>ell’<strong>in</strong>terfaccia I1, <strong>in</strong> quanto essa viene ere<strong>di</strong>tata da I3.Differenze tra <strong>in</strong>terfaccia e classe astrattaUn’<strong>in</strong>terfaccia e una classe astratta hanno <strong>in</strong> comune che possono contenere<strong>di</strong>chiarazioni <strong>di</strong> meto<strong>di</strong> senza fornirne l’implementazione. Nonostante questa19


somiglianza, che fa si che <strong>in</strong> alcune occasioni si posso sostituire una conl’altra, esistono anche alcune <strong>di</strong>fferenze importanti:• Una classe non può ere<strong>di</strong>tare da due classi astratte, pero può ere<strong>di</strong>tar<strong>ed</strong>a una classe astratta e implementare una o più <strong>in</strong>terfacce.• Una classe non può ere<strong>di</strong>tare meto<strong>di</strong> da un’<strong>in</strong>terfaccia.• Grazie alla possibilità <strong>di</strong> implementare più <strong>di</strong> una <strong>in</strong>terfaccia, questepermettono molta più flessibilità per ottenere che due classi abbianolo stesso comportamento, <strong>in</strong><strong>di</strong>pendentemente dalla posizione nella gerarchiadelle classi <strong>di</strong> <strong>Java</strong>.• Le <strong>in</strong>terfacce permettono <strong>di</strong> “rendere pubblico” il comportamento <strong>di</strong>una classe dando il m<strong>in</strong>imo <strong>di</strong> <strong>in</strong>formazioni.• Le <strong>in</strong>terfacce hanno una gerarchia propria, <strong>in</strong><strong>di</strong>pendente e più flessibil<strong>ed</strong>elle classi, <strong>in</strong> quanto è permessa l’ere<strong>di</strong>tarietà multipla.2.2 La gerarchia <strong>di</strong> CollectionVe<strong>di</strong>amo ora com’è strutturata la gerarchia <strong>di</strong> Collection, <strong>in</strong> quanto faremoriferimento a questa parte della libreria <strong>Java</strong> per <strong>in</strong>serire la classe Set <strong>di</strong>JSetL.Una collezione rappresenta un gruppo <strong>di</strong> oggetti (elementi della collezione).Le collezioni si possono sud<strong>di</strong>videre <strong>in</strong>:• collezioni che permettono elementi duplicati (come le liste) e collezioniche non lo permettono (come gli <strong><strong>in</strong>siemi</strong>);• collezioni <strong>in</strong> cui è importante l’or<strong>di</strong>ne (come le liste) e quelle <strong>in</strong> cuil’or<strong>di</strong>ne non importa (come gli <strong><strong>in</strong>siemi</strong>).<strong>Java</strong> non offre nessuna implementazione concreta dell’<strong>in</strong>terfaccia Collection:viene fornita l’implementazione <strong>di</strong> sotto<strong>in</strong>terfacce più specifiche, come appuntoSet e List. L’<strong>in</strong>terfaccia Collection è tipicamente usata per manipolarele collezioni dove è richiesta la massima generalità.20


Per capire meglio la gerarchia osserviamo il seguente <strong>di</strong>agramma <strong>di</strong> classiche rappresenta il sottoalbero <strong>di</strong> Collection riguardante gli <strong><strong>in</strong>siemi</strong>.L’<strong>in</strong>terfaccia Collection è la ra<strong>di</strong>ce della gerarchia. Collection viene ere<strong>di</strong>tatadall’<strong>in</strong>terfaccia Set e implementata dalla classe astratta AbstractCollection,che fornisce un’implementazione ridotta <strong>di</strong> Collection, implementando al-21


cuni meto<strong>di</strong> e <strong>di</strong>chiarando abstract i meto<strong>di</strong> iterator() e size().La classe astratta AbstractSet implementa Set <strong>ed</strong> estende AbstractCollection:il processo <strong>di</strong> implementazione è lo stesso che c’è tra Collection e AbstractCollection,con l’unica <strong>di</strong>fferenza che tutti i meto<strong>di</strong> devono osservare un v<strong>in</strong>colo aggiuntivoimposto dall’<strong>in</strong>terfaccia Set, ovvero rispettare l’unicità degli elementi nell’<strong>in</strong>sieme.In particolare AbstractSet sovrascrive il metodo removeAll(Collectionc) <strong>di</strong> AbstractCollection e aggiunge l’implementazione <strong>di</strong> equals() ehashCode().L’<strong>in</strong>terfaccia Sort<strong>ed</strong>Set ere<strong>di</strong>ta da Set e aggiunge meto<strong>di</strong> che garantisconoche i suoi elementi si mantegano or<strong>di</strong>nati secondo l’or<strong>di</strong>ne naturale o secondoun criterio stabilito.Inf<strong>in</strong>e le classi HashSet (implementata me<strong>di</strong>ante tabelle hash), TreeSet(implementata me<strong>di</strong>ante un albero b<strong>in</strong>ario or<strong>di</strong>nata) e la classe astrattaEnumSet estendono AbstractSet, <strong>in</strong> particolare TreeSet implementa ancheSort<strong>ed</strong>Set.2.3 L’<strong>in</strong>terfaccia java.util.SetIn generale, un <strong>in</strong>sieme è una collezione <strong>in</strong> cui:1. gli elementi duplicati non contano, ad esempio gli <strong><strong>in</strong>siemi</strong> {1, 1, 2},{1, 2, 2} sono uguali e identificano entrambi l’<strong>in</strong>sieme {1, 2};2. non importa l’or<strong>di</strong>ne degli elementi, ad esempio gli <strong><strong>in</strong>siemi</strong> {1, 2} e{2, 1} si equivalgono.L’<strong>in</strong>terfaccia Set, che come suggerisce il nome modella l’astrazione matematica<strong>di</strong> <strong>in</strong>sieme, estende l’<strong>in</strong>terfaccia Collection e offre tutti e soli i suoimeto<strong>di</strong>, con la restrizione che le classi che implementano Set si “impegnano”a non ammettere la presenza <strong>di</strong> elementi duplicati.Ve<strong>di</strong>amo quali sono i meto<strong>di</strong>, la loro funzione e un breve esempio per ciascuno<strong>di</strong> essi:22


• boolean add(Object o): aggiunge all’<strong>in</strong>sieme l’oggetto passato comeparametro; ritorna true se l’<strong>in</strong>sieme è cambiato dopo la chiamata aquesto metodo. Ad esempio: o ∈ sSet s1 = new HashSet();s1.add(1); // true: s1 = [1]s1.add(2); // true: s1 = [1,2]s1.add(1); // false: s1 = [1,2]Si noti che <strong>in</strong> <strong>Java</strong> gli <strong><strong>in</strong>siemi</strong> sono rappresentati con le parentesiquadre.• boolean addAll(Collection c): aggiunge all’<strong>in</strong>sieme tutti gli elementidella collezione passata come parametro (implementando cosìuna forma <strong>di</strong> unione: i.addAll(c) significa i ← i∪c, dove i è l’oggetto<strong>di</strong> <strong>in</strong>vocazione e c la collezione passata come parametro); ritornatrue se l’<strong>in</strong>sieme è cambiato dopo l’<strong>in</strong>vocazione <strong>di</strong> questo metodo. Adesempio:Set s2 = new HashSet();s2.addAll(s1); // true: s2 = [1,2]s2.addAll(s1); // false: s2 = [1,2]• void clear(): rimuove tutti gli elementi dall’<strong>in</strong>sieme. Ad esempio:s2.clear(); // s2 = []• boolean conta<strong>in</strong>s(Object o): ritorna true se l’<strong>in</strong>sieme contiene unelemento uguale all’oggetto passato come parametro. Ad esempio:s1.conta<strong>in</strong>s(1); // trues1.conta<strong>in</strong>s(5); // false23


• boolean conta<strong>in</strong>sAll(Collection c): ritorna true se l’<strong>in</strong>sieme contienetutti gli elementi della collezione passata come parametro. Adesempio:s2.addAll(s1); // s2 = s1 = [1,2]s1.conta<strong>in</strong>sAll(s2); // trues2.add(3); // s2 = [1,2,3]s1.conta<strong>in</strong>sAll(s2); // false• boolean equals(Object o):l’oggetto o. Ad esempio:verifica l’uguaglianza tra l’<strong>in</strong>sieme es1.equals(s2); // false (s1 = [1,2] e s2 = [1,2,3])s1.add(3); // s1 = [1,2,3]s1.equals(s2); // true• boolean isEmpty(): ritorna true se l’<strong>in</strong>sieme è vuoto. Ad esempio:s2.isEmpty();s2.clear();s2.isEmpty();// false// true• Iterator iterator():sugli elementi dell’<strong>in</strong>sieme. Ad esempio:restituisce un oggetto Iterator, per iterareIterator it = s1.iterator(); // s1 = [1,2,3]while(it.hasNext)System.out.pr<strong>in</strong>tln(it.next + " "); // 3 2 1• <strong>in</strong>t size(): ritorna il numero <strong>di</strong> elementi presenti nell’<strong>in</strong>sieme. Adesempio:s1.size(); // s1 = [1,2,3], size = 324


• boolean remove(Object o): rimuove dall’<strong>in</strong>sieme gli elementi ugualiall’oggetto passato come parametro. Ritorna true se l’<strong>in</strong>sieme è cambiatodopo l’<strong>in</strong>vocazione del metodo. Ad esempio:s1.remove(1); // true: s1 = [2, 3]s1.remove(5);// false• boolean removeAll(Collection c): rimuove dall’<strong>in</strong>sieme tutti glielementi uguali a quelli che sono contenuti nella collezione passatacome parametro (implementando così una forma <strong>di</strong> <strong>di</strong>fferenza: i.removeAll(c)significa i ← i \ c, dove i è l’oggetto <strong>di</strong> <strong>in</strong>vocazione e c la collezionepassata come parametro); ritorna true se l’<strong>in</strong>sieme è cambiato dopol’<strong>in</strong>vocazione <strong>di</strong> questo metodo. Ad esempio:s1.removeAll(s2); // false: s1 = [2,3] e s2 = []s2.addAll(s1); // s1 = s2 = [2,3]s2.add(4); // s2 = [2,3,4]s2.removeAll(s1); // true: s2 = [4]• boolean reta<strong>in</strong>All(Collection c): rimuove dall’<strong>in</strong>sieme tutti glielementi che non sono presenti nella collezione passata come parametro(implementando così una forma <strong>di</strong> <strong>in</strong>tersezione: i.reta<strong>in</strong>All(c) significai ← i ∩ c, dove i è l’oggetto <strong>di</strong> <strong>in</strong>vocazione e c la collezionepassata come parametro); ritorna true se l’<strong>in</strong>sieme è cambiato dopol’<strong>in</strong>vocazione <strong>di</strong> questo metodo. Ad esempio:s1.reta<strong>in</strong>All(s2); // true: s1 = []s1.addAll(s2); // s1 = s2 = [4]s1.reta<strong>in</strong>All(s2); // false: s1 = s2 = [4]25


2.4 Implementazione <strong>di</strong> SetL’<strong>in</strong>terfaccia Set viene implementata dalla classe astratta AbstractSet,che è superclasse delle sottoclassi HashSet, TreeSet, EnumSet. Ve<strong>di</strong>amo<strong>in</strong> particolare le prime due classi.2.4.1 HashSetpublic class HashSet extends AbstractSet implements SetQuesta classe implementa l’<strong>in</strong>terfaccia Set e gestisce un <strong>in</strong>sieme nonor<strong>di</strong>nato me<strong>di</strong>ante tabelle hash con liste concatenate. Gli oggetti vengono<strong>in</strong>seriti <strong>in</strong> posizioni della tabella che <strong>di</strong>pendono dalla funzione <strong>di</strong> hashadottata.Una funzione <strong>di</strong> hash è una funzione che calcola un numero <strong>in</strong>tero, co<strong>di</strong>cehash, a partire dai dati <strong>di</strong> un oggetto, <strong>in</strong> modo che sia molto probabile cheoggetti non uguali abbiano co<strong>di</strong>ci <strong>di</strong>versi. Due o più oggetti possono averelo stesso co<strong>di</strong>ce <strong>di</strong> hash: questa situazione genera una collisione. Una buonafunzione <strong>di</strong> hash deve m<strong>in</strong>imizzare le collisioni. Se i co<strong>di</strong>ci hash sono <strong>di</strong>versiallora gli elementi non sono uguali; il contrario non è necessariamente vero.Le funzioni <strong>di</strong> hash vengono usate per creare collezioni (mappe e <strong><strong>in</strong>siemi</strong>)su cui poter operare <strong>in</strong> modo molto efficiente. L’idea è quella <strong>di</strong> avere unarray i cui <strong>in</strong><strong>di</strong>ci siano i co<strong>di</strong>ci hash degli elementi. Questa idea però ha dueproblemi:1. La <strong>di</strong>mensione dell’array2. Le collisioniPer ovviare al primo problema si deve scegliere una funzione <strong>di</strong> hash chegeneri co<strong>di</strong>ci <strong>in</strong> un range ragionevolmente ridotto; per ovviare al secondoproblema si usano liste concatenate. Se la funzione <strong>di</strong> hash è ben def<strong>in</strong>ita(range piccolo e poche collisioni) le <strong>operazioni</strong> <strong>di</strong> ricerca, verifica <strong>di</strong> appartenenza,rimozione, <strong>in</strong>serimento <strong>in</strong> una collezione hanno costo costante; le<strong>operazioni</strong> <strong><strong>in</strong>siemi</strong>stiche hanno complessità l<strong>in</strong>eare.26


In <strong>Java</strong> il co<strong>di</strong>ce hash <strong>di</strong> un oggetto deve essere restituito dal metodohashCode(). Se vogliamo usare l’implementazione HashSet <strong>di</strong> Set, gli oggettidella collezione devono avere i meto<strong>di</strong> hashCode() e equals() def<strong>in</strong>iti opportunamente.In s<strong>in</strong>tesi, per verificare la presenza <strong>di</strong> duplicati HashSet usaequals() <strong>in</strong> comb<strong>in</strong>azione con il valore restituito dal metodo hashCode().In particolare, per verificare se due oggetti sono uguali, HashSet prima verificase il loro co<strong>di</strong>ce hash è identico: solo <strong>in</strong> caso affermativo (collisione)viene <strong>in</strong>vocato il metodo equals().Il metodo remove() senza argomento si riferisce all’<strong>in</strong>terfaccia Iterator.Quest’ultimo metodo evita mo<strong>di</strong>fiche concorrenti che possano <strong>in</strong>terferire conaltre istanze <strong>di</strong> iteratori me<strong>di</strong>ante contatori <strong>di</strong> mo<strong>di</strong>fiche. HashSet non dàgaranzie sull’or<strong>di</strong>ne <strong>di</strong> iterazione dell’<strong>in</strong>sieme; <strong>in</strong> particolare, non garantisceche l’or<strong>di</strong>ne rimarrà costante nel tempo. Questa classe permette gli element<strong>in</strong>ulli.2.4.2 TreeSetpublic class TreeSet extends AbstractSet implements Sort<strong>ed</strong>SetLa classe TreeSet implementa l’<strong>in</strong>terfaccia Set e gestisce gli <strong><strong>in</strong>siemi</strong>or<strong>di</strong>nati me<strong>di</strong>ante alberi b<strong>in</strong>ari <strong>di</strong> ricerca non bilanciati. L’implementazione<strong>di</strong> TreeSet garantisce (oltre all’assenza <strong>di</strong> duplicati) che gli elementi sianoor<strong>di</strong>nati <strong>in</strong> accordo con:- l’or<strong>di</strong>namento naturale <strong>in</strong>terno, oppure- un or<strong>di</strong>namento esterno stabilito da un comparatore e noto all’<strong>in</strong>siemestesso (ad esempio perché ricevuto al momento della sua creazioneattraverso uno dei suoi molteplici costruttori).Il criterio <strong>di</strong> equivalenza tra elementi si basa sul metodo compareTo() ocompare() (<strong>di</strong> una classe esterna). Gli oggetti dell’<strong>in</strong>sieme devono fornire ilmetodo compareTo() dell’<strong>in</strong>terfaccia standard Comparable per mantenerele chiavi or<strong>di</strong>nate. L’eccezione IllegalArgumentException viene generatase gli oggetti non sono tutti Comparable.27


È possibile, <strong>in</strong>f<strong>in</strong>e, creare un iteratore Iterator che scan<strong>di</strong>sce gli oggetti<strong>in</strong> maniera crescente secondo l’or<strong>di</strong>ne specificato. Il metodo remove() senzaargomento si riferisce all’<strong>in</strong>terfaccia Iterator. Quest’ultimo metodo evitamo<strong>di</strong>fiche concorrenti che possano <strong>in</strong>terferire con altre istanze <strong>di</strong> iteratorime<strong>di</strong>ante contatori <strong>di</strong> mo<strong>di</strong>fiche.L’<strong>in</strong>serzione, la ricerca e la cancellazione hanno complessità logaritmicarispetto al numero <strong>di</strong> elementi; le <strong>operazioni</strong> <strong><strong>in</strong>siemi</strong>stiche hanno complessitàl<strong>in</strong>eare.28


Capitolo 3IntegrazioneIn questo capitolo descriviamo l’architettura complessiva del nuovo packageJSetL e le <strong>in</strong>terfacce <strong>Java</strong> create. Le classi che implementano le <strong>in</strong>terfaccesono descritte nei successivi capitoli.3.1 MotivazioniLo scopo del lavoro è <strong>di</strong> creare un’unica astrazione <strong>di</strong> <strong>in</strong>sieme su cui poteroperare sia con i meto<strong>di</strong> forniti da java.util.Set che con quelli <strong>di</strong> JSetL,limitando al m<strong>in</strong>imo le mo<strong>di</strong>fiche al package JSetL. Il nuovo package JSetLdeve fornire qu<strong>in</strong><strong>di</strong> anche tutte le funzionalità degli <strong><strong>in</strong>siemi</strong> <strong>di</strong> <strong>Java</strong>, mantenendola piena compatibilità con applicazioni scritte usando le prec<strong>ed</strong>entilibrerie (a meno <strong>di</strong> nomi).Per gli <strong><strong>in</strong>siemi</strong> completamente specificati bisogna garantire che la semanticadele <strong>operazioni</strong> sugli <strong><strong>in</strong>siemi</strong> <strong>di</strong> <strong>Java</strong> sia la stessa prevista dall’<strong>in</strong>terfacciajava.util.Set. Questo deve essere vero anche se l’<strong>in</strong>sieme è costruito a partir<strong>ed</strong>a un “logical set” contenente variabili logiche <strong>in</strong>izializzate; ad esempiose sull’<strong>in</strong>sieme s così def<strong>in</strong>ito:s = {1, x, 4}, con x variabile logica con valore 3viene richiamato il metodo conta<strong>in</strong>s <strong>di</strong> java.util.Set29


s.conta<strong>in</strong>s(3);deve essere restituito true come risultato.I meto<strong>di</strong> <strong>di</strong> utilità previsti <strong>in</strong> JSetL con comportamento “extra logico”verranno rimpiazzati, quando possibile, dai corrispondenti meto<strong>di</strong> <strong>di</strong>java.util.Set. Ad esempio:• Il metodo concat può essere sostituito dal metodo addAll;• Il metodo sub può essere sostituito dal metodo remove.Mentre i meto<strong>di</strong> isEmpty, size e clear presenti sia <strong>in</strong> java.util.Set che<strong>in</strong> JSetL, con semantica sostanzialmente identica, possono essere fusi <strong>in</strong>sieme.Su <strong><strong>in</strong>siemi</strong> qualsiasi (completamente e parzialmente specificati, limitati e illimitati)deve rimanere possibile operare con le <strong>operazioni</strong> previste da JSetL,<strong>in</strong> particolare con i v<strong>in</strong>coli <strong><strong>in</strong>siemi</strong>stici forniti da JSetL.3.2 ArchitetturaSi vuole aggiungere a JSetL una classe che implementi i meto<strong>di</strong> dell’<strong>in</strong>terfacciajava.util.Set e nello stesso tempo possi<strong>ed</strong>a tutte le funzioni <strong>di</strong>JSetL.Set. Per fare questo def<strong>in</strong>iamo due <strong>in</strong>terfacce: LSet (“Logical Set”)e MutableLSet. La prima contiene tutti i meto<strong>di</strong> public <strong>di</strong> JSetL.Set; laseconda estende le <strong>in</strong>terfacce LSet e java.util.Set, ere<strong>di</strong>tandone tutti imeto<strong>di</strong>.Ve<strong>di</strong>amo la gerarchia <strong>di</strong> queste tre <strong>in</strong>terfacce:30


Un <strong>in</strong>sieme <strong>in</strong> LSet è considerato un oggetto immutabile, ovvero qualsiasioperazione su <strong>di</strong> esso non mo<strong>di</strong>fica mai l’oggetto, ma piuttosto ne viene fattauna copia. MutableLSet <strong>in</strong>vece viene chiamata mutabile proprio perché siprev<strong>ed</strong>e che l’oggetto chiamante possa essere mo<strong>di</strong>ficato, <strong>in</strong> quanto i meto<strong>di</strong><strong>di</strong> java.util.Set mo<strong>di</strong>ficano l’oggetto <strong>di</strong> <strong>in</strong>vocazione.Per mantere non visibili i meto<strong>di</strong> protecet<strong>ed</strong> al <strong>di</strong> fuori del packageaggiungiamo anche l’<strong>in</strong>terfaccia LSetProtect<strong>ed</strong>, con visibilità package, cheestende LSet.Le classi concrete sono due: ConcreteLSet, che implementa l’<strong>in</strong>terfacciaLSetProtect<strong>ed</strong> <strong>ed</strong> è sostanzialmente la classe JSetL.Set orig<strong>in</strong>ale cambiata<strong>di</strong> nome e con alcune mo<strong>di</strong>fiche; ConcreteMutableLSet, che implementaLSetProtect<strong>ed</strong> e MutableLSet.Ve<strong>di</strong>amo il <strong>di</strong>agramma <strong>di</strong> classi dove vengono rappresentate le <strong>in</strong>terfaccee le classi che le implementano:31


Questa architettura permette <strong>di</strong> creare, attraverso l’<strong>in</strong>terfaccia MutableLSetun oggetto che possa utilizzare sia i meto<strong>di</strong> <strong>di</strong> java.util.Set, che quelli <strong>di</strong>LSet:MutableLSet s1 = new ConcreteMutableLSet();Questo è il modo più generico per costruire un <strong>in</strong>sieme, <strong>in</strong> quanto s1 forniscesia le funzionalità degli <strong><strong>in</strong>siemi</strong> <strong>in</strong> <strong>Java</strong> che quelle degli <strong><strong>in</strong>siemi</strong> <strong>in</strong> JSetL epuò essere <strong>in</strong>serito senza problemi <strong>di</strong> compatibilità <strong>in</strong> entrambi i contesti.Inoltre è possibile creare oggetti che possano utilizzare rispettivamente imeto<strong>di</strong> delle due <strong>in</strong>terfacce:- LSet s2 = new ConcreteLSet();In questo modo viene creato un <strong>in</strong>sieme s2 con le stesse potenzialità e32


gli stessi meto<strong>di</strong> della classe orig<strong>in</strong>ale JSetL.Set (equivale all’orig<strong>in</strong>aleSet s2 = new Set();)- java.util.Set s3 = new ConcreteMutableLSet();L’<strong>in</strong>sieme s3 può utilizzare tutti e soli i meto<strong>di</strong> dell’<strong>in</strong>terfaccia Set <strong>di</strong><strong>Java</strong>, che vengono implementati nella classe ConcreteMutableLSet.Questa classe può essere considerata un’ulteriore implementazione <strong>di</strong>java.util.Set, come HashSet e TreeSet.3.3 L’<strong>in</strong>terfaccia LSetL’<strong>in</strong>terfaccia LSet è pubblica e contiene tutti i meto<strong>di</strong> public dell’orig<strong>in</strong>aleclasse JSetL.Set.public <strong>in</strong>terface LSet {}// <strong>di</strong>chiarazione dei meto<strong>di</strong> public <strong>di</strong> JSetL.SetVe<strong>di</strong>amo <strong>in</strong> particolare quali attributi e meto<strong>di</strong> contiene.AttributiCome abbiamo visto nella sezione 2.1, un’<strong>in</strong>terfaccia <strong>in</strong> <strong>Java</strong> può conteneresolo attributi costanti. LSet contiene un solo attributo costante pubblico:public static f<strong>in</strong>al ConcreteLSet empty =new ConcreteLSet("emptySet", null, null);L’attributo empty è un ConcreteLSet e richiama un costruttore <strong>di</strong> ConcreteLSetper creare l’<strong>in</strong>sieme vuoto.Meto<strong>di</strong>I meto<strong>di</strong> dell’<strong>in</strong>terfaccia LSet si possono sud<strong>di</strong>videre <strong>in</strong> 2 categorie:33


1. meto<strong>di</strong> <strong>di</strong> vario utilizzo: <strong>in</strong>s, <strong>in</strong>sAll, clone, isEmpty, equals,isBound, toVector, size, concat, output, pr<strong>in</strong>t, isGround, known,read, normalizeSet, toStr<strong>in</strong>g, first, setName, getName, getValue,get.2. meto<strong>di</strong> <strong>di</strong> generazione <strong>di</strong> v<strong>in</strong>coli: sono meto<strong>di</strong> che permettono <strong>di</strong>creare v<strong>in</strong>coli che svolgono <strong>operazioni</strong> <strong><strong>in</strong>siemi</strong>stiche, tra cui: uguaglianza(eq) e <strong>di</strong>suguaglianza (neq), appartenenza (<strong>in</strong>) e non appartenenza(n<strong>in</strong>), <strong>in</strong>clusione (subset) e non <strong>in</strong>clusione (nsubset), unione(union) e non unione (nunion), <strong>in</strong>tersezione (<strong>in</strong>ters) e non <strong>in</strong>tersezione(n<strong>in</strong>ters), <strong>di</strong>sgiunzione (<strong>di</strong>sj) e non <strong>di</strong>sgiunzione (n<strong>di</strong>sj),<strong>di</strong>fferenza (<strong>di</strong>ffer) e non <strong>di</strong>fferenza (n<strong>di</strong>ffer), sottrazione (less,less1).I meto<strong>di</strong>, che nella <strong>di</strong>chiarazione hanno un <strong>in</strong>sieme come tipo <strong>di</strong> ritornoo come parametro, utilizzano l’<strong>in</strong>terfaccia LSet, <strong>in</strong> quanto è visibile anch<strong>ed</strong>all’esterno del package. Ve<strong>di</strong>amo ad esempio i meto<strong>di</strong> <strong>in</strong>s e <strong>in</strong> comevengono <strong>di</strong>chiarati:public LSet <strong>in</strong>s(Object o);public Constra<strong>in</strong>t <strong>in</strong> (LSet set);3.4 L’<strong>in</strong>terfaccia LSetProtect<strong>ed</strong>L’<strong>in</strong>terfaccia LSetProtect<strong>ed</strong> è stata aggiunta <strong>in</strong> quanto necessaria per manterenon visibili al <strong>di</strong> fuori del package i meto<strong>di</strong> protect<strong>ed</strong> <strong>di</strong> JSetL.Set.In un’<strong>in</strong>terfaccia tutti i meto<strong>di</strong> devono essere public, ma la loro visibilità<strong>di</strong>pende dalla visibilità dell’<strong>in</strong>terfaccia stessa. LSetProtect<strong>ed</strong> è stata def<strong>in</strong>itacon visibilità package, ovvero non anteponendo niente alla parola <strong>in</strong>terface:<strong>in</strong>terface LSetProtect<strong>ed</strong> extends LSet {}// <strong>di</strong>chiarazione dei meto<strong>di</strong> protect<strong>ed</strong>34


In questo modo LSetProtect<strong>ed</strong> è visibile e pertanto utilizzabile solo all’<strong>in</strong>ternodel package. Questa <strong>in</strong>terfaccia estende LSet e viene a sua voltaimplementata da ConcreteMutableLSet e ConcreteLSet.AttributiL’<strong>in</strong>terfaccia LSetProtect<strong>ed</strong> contiene gli attributi constanti private orig<strong>in</strong>alidella classe JSetL.Set:static Str<strong>in</strong>g prefix = "LSet_";static Vector nonInizSet = new Vector();static SolverClass solver = new SolverClass();• prefix è una str<strong>in</strong>ga e viene <strong>in</strong>izializzata con “LSet ”, a cui vieneconcatenato un numero sempre crescente, per dare un nome univocoa ogni LSet che viene creato;• nonInizSet è un vettore che viene creato vuoto e <strong>in</strong> cui viene <strong>in</strong>seritol’oggetto <strong>di</strong> <strong>in</strong>vocazione se questo è non <strong>in</strong>izializzato(if(!<strong>in</strong>iz) nonInizSet.add(this));• solver è un oggetto della classe SolverClass e viene utilizzato perrisolvere i v<strong>in</strong>coli.Meto<strong>di</strong>Anche i meto<strong>di</strong> <strong>di</strong> LSetProtect<strong>ed</strong> si possono sud<strong>di</strong>videre <strong>in</strong> 2 categorie:• meto<strong>di</strong> <strong>di</strong> tipo set e get: i meto<strong>di</strong> set e get rispettivamente impostanoe restituiscono un attributo non costante della classe concretache implementa l’<strong>in</strong>terfaccia LSet, tra cui: <strong>in</strong>iz, lista, resto, equ,isInt, <strong>in</strong>ter, id, counter.• meto<strong>di</strong> <strong>di</strong> vario utilizzo non visibili fuori dal package: sub,subfirst, sost, appendGround, append, occurs, conta<strong>in</strong>s, isEmptySL,ultimoResto, value.35


I meto<strong>di</strong>, che nella <strong>di</strong>chiarazione hanno un <strong>in</strong>sieme come tipo <strong>di</strong> ritorno ocome parametro, utilizzano l’<strong>in</strong>terfaccia LSetProtect<strong>ed</strong>, <strong>in</strong> quanto è visibilesolo all’<strong>in</strong>terno del package. Ve<strong>di</strong>amo ad esempio come viene <strong>di</strong>chiarato ilmetodo append:public LSetProtect<strong>ed</strong> append(LSetProtect<strong>ed</strong> set);L’<strong>in</strong>terfaccia LSetProtect<strong>ed</strong> viene nascosta all’esterno e viene solo utilizzataper l’implementazione <strong>in</strong>terna.3.5 L’<strong>in</strong>terfaccia MutableLSetL’<strong>in</strong>terfaccia MutableLSet viene chiamata così <strong>in</strong> quanto la sua implementazionecrea degli oggetti che sono mutabili, cioè che attraverso una chiamataa un metodo l’oggetto <strong>di</strong> <strong>in</strong>vocazione può essere mo<strong>di</strong>ficato, mentrecon LSet viene creato un oggetto nuovo. Questa <strong>in</strong>terfaccia ere<strong>di</strong>ta i meto<strong>di</strong>delle <strong>in</strong>terfacce java.util.Set e LSet, senza aggiungerne <strong>di</strong> nuovi. La suadef<strong>in</strong>izione è la seguente:public <strong>in</strong>terface MutableLSet extends java.util.Set, LSet{ }In quanto MutableLSet è un <strong>in</strong>terfaccia, può estendere più <strong>in</strong>terfacce,cosa che non è possibile tra le classi, ovvero una classe può ere<strong>di</strong>tare al piùda un’altra classe.36


Capitolo 4Implementazione: la classeConcreteLSetLa classe ConcreteLSet implementa l’<strong>in</strong>terfaccia LSetProtect<strong>ed</strong> (e perere<strong>di</strong>tarietà anche l’<strong>in</strong>terfaccia LSet), <strong>ed</strong> è stata creata utilizzando la classeSet orig<strong>in</strong>ale <strong>di</strong> JSetL, mo<strong>di</strong>ficandola <strong>in</strong> alcune sue parti e cambiandole ilnome per renderlo più esplicativo: “Concrete” perché è una classe concretae “LSet” (Logical Set) per sottol<strong>in</strong>eare che è un <strong>in</strong>sieme logico.public class ConcreteLSet implements java.io.Serializable, LSetProtect<strong>ed</strong> {// attributi// costruttori// implementazione meto<strong>di</strong> <strong>di</strong> LSetProtect<strong>ed</strong> e LSet}Ve<strong>di</strong>amo più nel particolare la classe ConcreteLSet.4.1 AttributiGli attributi costanti della classe orig<strong>in</strong>ale (prefix, nonInizSet, solver <strong>ed</strong>empty) sono stati, <strong>in</strong>seriti e <strong>in</strong>izializzati nelle <strong>in</strong>terfacce LSet e LSetProtect<strong>ed</strong>.Gli altri attributi sono <strong>in</strong>vece rimasti <strong>in</strong>variati, e sono:37


protect<strong>ed</strong> boolean <strong>in</strong>iz = false;protect<strong>ed</strong> Vector lista;protect<strong>ed</strong> LSet resto;protect<strong>ed</strong> LSet equ = null;protect<strong>ed</strong> Int <strong>in</strong>ter = null;protect<strong>ed</strong> boolean isInt = false;protect<strong>ed</strong> Str<strong>in</strong>g name = null;protect<strong>ed</strong> <strong>in</strong>t id;private static <strong>in</strong>t counter = 0;L’attributo <strong>in</strong>iz <strong>in</strong><strong>di</strong>ca se l’<strong>in</strong>sieme è <strong>in</strong>izializzato o no: <strong>di</strong> default è non<strong>in</strong>izializzato (false). I campi lista e resto servono per memorizzare ilvalore dell’<strong>in</strong>sieme. lista è un riferimento ad un vettore e contiene gli elementidell’<strong>in</strong>sieme; resto è un riferimento ad un oggetto LSet e contiene ilresto non specificato dell’<strong>in</strong>sieme. Il campo equ, <strong>in</strong>izializzato a null, è unriferimento ad un altro oggetto LSet. Questo attributo è stato <strong>in</strong>trodottoper rendere più efficiente la propagazione dei v<strong>in</strong>coli. Il campo <strong>in</strong>ter è unoggetto <strong>di</strong> tipo Int (classe <strong>di</strong> JSetL che implementa l’astrazione degli <strong>in</strong>tervalli)<strong>ed</strong> è null <strong>di</strong> default, altrimenti gli viene assegnato l’<strong>in</strong>tervallo passatonel costruttore corrispondente. Per verificare che l’<strong>in</strong>sieme sia formato daun <strong>in</strong>tervallo si utilizza l’attributo booleano isInt che ha valore true se l’<strong>in</strong>siemeè un <strong>in</strong>tervallo, false altrimenti. L’attributo name è una str<strong>in</strong>ga chememorizza il nome dell’<strong>in</strong>sieme: si può assegnare il nome passandolo comeparametro quando viene costruito un oggetto, oppure gli viene assegnatoil nome <strong>di</strong> default “LSet ” seguito dal numero univoco id, un <strong>in</strong>tero a cuiviene assegnato il valore <strong>di</strong> counter, attributo statico che viene <strong>in</strong>izializzatoa 0 e <strong>in</strong>crementato ogni volta che viene creato un oggetto.4.2 CostruttoriVe<strong>di</strong>amo quali sono i costruttori per creare un oggetto <strong>di</strong> tipo ConcreteLSet.Innanzi tutto commentiamo il costruttore senza parametri:38


public ConcreteLSet() {this.lista = null;this.resto = null;this.id = counter++;nonInizSet.add(this);this.name = prefix.concat((new Integer(this.id)).toStr<strong>in</strong>g());}Gli attributi lista e resto vengono <strong>in</strong>izializzati a null, <strong>in</strong> quantol’<strong>in</strong>sieme non contiene nessun elemento. All’id viene assegnato il valore<strong>di</strong> counter <strong>in</strong>crementato <strong>di</strong> uno. Al vettore nonInizSet viene aggiuntol’oggetto non <strong>in</strong>izializzato. Inf<strong>in</strong>e il nome sarà la concatenazione tra prefix(“LSet ”) e l’id.In secondo luogo ve<strong>di</strong>amo i costruttori con un parametro. Ve<strong>di</strong>amo adesempio la def<strong>in</strong>izione <strong>di</strong> un costruttore che prende come parametro un array:public ConcreteLSet(tipo[] arr) {...}dove per “tipo” si <strong>in</strong>tendono Object e i tipi primitivi boolean, byte, char,double, float, <strong>in</strong>t, long, short. Ve<strong>di</strong>amo come si comporta uno <strong>di</strong> questicostruttori, ad esempio quello che prende un array <strong>di</strong> <strong>in</strong>teri come parametro:private Vector wrapperSet() {Vector v = new Vector();this.<strong>in</strong>iz = true;this.resto = ConcreteLSet.empty;this.id = counter++;return v;}public ConcreteLSet(<strong>in</strong>t[] arr) {Vector v = this.wrapperSet();39


}for(<strong>in</strong>t i = 0; i < arr.length; i++) {Integer ii = new Integer(arr[i]);v.add(ii);}this.lista = v;this.name = prefix.concat((new Integer(this.id)).toStr<strong>in</strong>g());La prima cosa che il costruttore fa è creare un vettore richiamando il metodoprivato wrapperSet, che crea un vettore vuoto, imposta la variabile <strong>in</strong>iza true per <strong>in</strong><strong>di</strong>care che l’<strong>in</strong>sieme è <strong>in</strong>izializzato, l’attributo resto vieneanch’esso <strong>in</strong>izializzato e creato vuoto, la variabile id assume il suo valor<strong>ed</strong>a counter e <strong>in</strong>f<strong>in</strong>e restituisce un vettore. In secondo luogo il costruttorescorre gli elementi dell’array, crea un oggetto della classe corrispondenteal tipo primitivo utilizzato (a parte nel caso <strong>di</strong> Object) e aggiunge ognielemento al vettore. Inf<strong>in</strong>e all’attributo lista viene assegnato il valore delvettore e a name il nome dell’oggetto.Gli altri tipi <strong>di</strong> costruttori con un parametro della classe ConcreteLSetsono:public ConcreteLSet(Str<strong>in</strong>g n) {...}public ConcreteLSet(Int I) {...}public ConcreteLSet(LSet s) {...}public ConcreteLSet(Lst l) {...}public ConcreteLSet(Lvar l) {...}Nel primo viene richiamato il costruttore vuoto con this() e all’attributoname viene assegnata la str<strong>in</strong>ga passata come parametro. Nel secondo casol’<strong>in</strong>sieme è <strong>in</strong>izializzato (<strong>in</strong>iz = true), alla variabile isInt viene assegnatoil valore true, a <strong>in</strong>ter viene assegnato l’<strong>in</strong>tervallo passato, lista e restosono nulli e id e name vengono <strong>in</strong>izializzati come sempre. Il terzo costruttoreassegna il valore degli attributi dell’<strong>in</strong>sieme passato agli attributi dell’oggettochiamante, <strong>in</strong> particolare equ viene uguagliato all’<strong>in</strong>sieme s. Negli ultimi40


due costruttori viene creato un vettore richiamando il metodo wrapp<strong>ed</strong>Set ead esso viene aggiunta la variabile logica o la lista (v.add(l)) e viene creatoil nome.I costruttori con due parametri creano tutti gli oggetti già creati daicostruttori con un parametro e <strong>in</strong> più viene assegnato loro un nome. Ingenerale l’implementazione è la seguente:public ConcreteLSet(Str<strong>in</strong>g n, tipo t) {this(t);this.name = n;}Vi sono altri due costruttori con due parametri con i rispettivi costruttoricon tre parametri che <strong>in</strong> più prendono una str<strong>in</strong>ga, che rappresenta il nom<strong>ed</strong>ell’<strong>in</strong>sieme. Essi sono:public ConcreteLSet(<strong>in</strong>t p, <strong>in</strong>t q) {...}public ConcreteLSet(<strong>in</strong>t p, Lvar q) {...}public ConcreteLSet(Str<strong>in</strong>g n, <strong>in</strong>t p, <strong>in</strong>t q) {...}public ConcreteLSet(Str<strong>in</strong>g n, <strong>in</strong>t p, Lvar q) {...}Entrambi creano un <strong>in</strong>sieme con gli elementi <strong>di</strong> un <strong>in</strong>tervallo, con la <strong>di</strong>fferenzache nel primo e nel terzo vengono passati due <strong>in</strong>teri estremi dell’<strong>in</strong>tervallo,mentre nel secondo e nel quarto si può passare una variabile logica il cuivalore rappresenta il limite superiore dell’<strong>in</strong>sieme.Inf<strong>in</strong>e vi è un costruttore protetto che prende come parametri un vettoree un <strong>in</strong>sieme (vi è anche il costruttore corrispondente con <strong>in</strong> più una str<strong>in</strong>gacome parametro per il nome):protect<strong>ed</strong> ConcreteLSet(Vector v, LSet s) {...}protect<strong>ed</strong> ConcreteLSet(Str<strong>in</strong>g n, Vector v, LSet s) {...}41


Questo costruttore prima <strong>di</strong> tutto controlla se il vettore e l’<strong>in</strong>sieme sononulli, <strong>in</strong> tal caso <strong>in</strong>iz è <strong>in</strong>izializzata a true e lista e resto a null; altrimentialla variabile lista viene assegnato il vettore v e a resto l’<strong>in</strong>sieme s.Inoltre se la <strong>di</strong>mensione della lista è positiva, allora l’attributo <strong>in</strong>iz <strong>di</strong>ventatrue, altrimenti gli viene assegnato il valore <strong>di</strong> <strong>in</strong>iz dell’<strong>in</strong>sieme s. Inf<strong>in</strong>e sicontrolla ancora se <strong>in</strong>iz è uguale a true e se non lo è l’oggetto chiamanteviene <strong>in</strong>serito nel vettore nonInizSet; id e name vengono <strong>in</strong>izializzati nelsolito modo.4.3 Implementazione dei meto<strong>di</strong> <strong>di</strong> LSet e LSetProtect<strong>ed</strong>4.3.1 Meto<strong>di</strong> <strong>di</strong> tipo set e getI meto<strong>di</strong> <strong>di</strong> tipo set e get non esistono nella classe JSetL.Set orig<strong>in</strong>ale esono stati aggiunti per dare la possibilità anche alla nuova classe ConcreteMutableLSet<strong>di</strong> poter richiamare e impostare gli attributi <strong>di</strong> ConcreteLSet. Ve<strong>di</strong>amo adesempio i meto<strong>di</strong> <strong>di</strong> tipo set e get per l’attributo lista:public Vector getLista() {return lista;}public void setLista(Vector lista) {this.lista = lista;}Il metodo getLista restituisce l’attributo lista, mentre il metodo setListaassegna all’attributo lista il valore passato come parametro.4.3.2 Meto<strong>di</strong> <strong>di</strong> vario utilizzoL’implementazione <strong>di</strong> questi meto<strong>di</strong> è quella prevista <strong>in</strong> JSetL. In particolareve<strong>di</strong>amo alcuni dettagli sull’implementazione dei meto<strong>di</strong> <strong>di</strong> <strong>in</strong>serimento e <strong>di</strong>estrazione.I meto<strong>di</strong> <strong>di</strong> <strong>in</strong>serimento <strong>di</strong> elementi <strong>in</strong> un <strong>in</strong>sieme sono due:42


public LSet <strong>in</strong>s(tipo n) {...}public LSet <strong>in</strong>sAll(tipo[] arr) {...}Il primo prende come parametro un tipo, che può essere un tipo primitivo,oppure un Object. Il metodo <strong>in</strong>s controlla se la variabile equ è ugualea null e <strong>in</strong> tal caso costruisce un vettore vuoto, vi aggiunge il parametron con il proprio metodo add, crea un LSet <strong>tramite</strong> il costruttore protettodella classe concreta ConcreteLSet che prende un vettore e un LSet e <strong>in</strong>f<strong>in</strong>erestituisce l’oggetto creato. Altrimenti, se l’attributo equ non è null, vienerichiamato il metodo stesso su equ (return this.equ.<strong>in</strong>s(n)).Il metodo <strong>in</strong>sAll ha come parametro un array, che può essere ancora unqualsiasi tipo primitivo o un Object. L’implementazione è molto simile allaprec<strong>ed</strong>ente, con la <strong>di</strong>fferenza che si scorre l’array con un ciclo for e viene<strong>in</strong>serito nel vettore creato un elemento alla volta.Il metodo <strong>di</strong> estrazione <strong>di</strong> elementi da un <strong>in</strong>sieme è il seguente:public LSet sub() {...}Il metodo sub restituisce un LSet privato del primo elemento dell’<strong>in</strong>sieme.Questo metodo, dal comportamento “extra logico”, può essere sostituitodal nuovo metodo addAll <strong>di</strong> java.util.Set, come viene spiegato piùavanti.Ai meto<strong>di</strong> già presenti <strong>in</strong> JSetL è stato aggiunto il metodo booleano isBound,che verifica se l’<strong>in</strong>sieme è illimitato.public boolean isBound() {if(getIniz() || ultimoResto().equals(ConcreteLSet.empty))return true;else return false;}43


Questo metodo controlla se l’<strong>in</strong>sieme è <strong>in</strong>izializzato o se la sua “coda”(data dal metodo booleano ultimoResto) è vuota: se una delle duecon<strong>di</strong>zioni sono verificate, l’<strong>in</strong>sieme è limitato e <strong>in</strong>izializzato.4.3.3 Meto<strong>di</strong> <strong>di</strong> generazione <strong>di</strong> v<strong>in</strong>coliNella classe ConcreteLSet è possibile costruire dei v<strong>in</strong>coli che verranno poi<strong>in</strong>seriti nel Constra<strong>in</strong>t Store e saranno risolti <strong>tramite</strong> il metodo Solve dellaclasse SolverClass. Ve<strong>di</strong>amo quali sono i meto<strong>di</strong> della classe ConcreteLSetche generano v<strong>in</strong>coli e il loro significato applicato a un LSet s:Uguaglianza e <strong>di</strong>suguaglianza:utilizzo metodo v<strong>in</strong>colo generatos.eq(o) public Constra<strong>in</strong>t eq(Object o) s = os.neq(o) public Constra<strong>in</strong>t neq(Object o) s ≠ oLess:utilizzo metodo v<strong>in</strong>colo generatos.less(l,ls) Constra<strong>in</strong>t less(Lvar l,Lvar ls) s ∈ ls ∧Constra<strong>in</strong>t less(Lvar l,LSet ls) ls = s \ {l}Appartenenza e non appartenenza:utilizzo metodo v<strong>in</strong>colo generatos.<strong>in</strong>(ls) Constra<strong>in</strong>t <strong>in</strong>(LSet ls) s ∈ lsConstra<strong>in</strong>t <strong>in</strong>(Lvar ls)s.n<strong>in</strong>(ls) Constra<strong>in</strong>t n<strong>in</strong>(LSet ls) s /∈ lsConstra<strong>in</strong>t n<strong>in</strong>(Lvar ls)Disgiunzione e non <strong>di</strong>sgiunzione:utilizzo metodo v<strong>in</strong>colo generatos.<strong>di</strong>sj(ls) Constra<strong>in</strong>t <strong>di</strong>sj(LSet ls) s ∩ ls ≠ ∅Constra<strong>in</strong>t <strong>di</strong>sj(Lvar ls)s.n<strong>di</strong>sj(ls) Constra<strong>in</strong>t n<strong>di</strong>sj(LSet ls) s ∩ ls = ∅Constra<strong>in</strong>t n<strong>di</strong>sj(Lvar ls)44


Inclusione e non <strong>in</strong>clusione:utilizzo metodo v<strong>in</strong>colo generatos.subset(ls) Constra<strong>in</strong>t subset(LSet ls) s ⊆ lsConstra<strong>in</strong>t subset(Lvar ls)s.nsubset(ls) Constra<strong>in</strong>t nsubset(LSet ls) s lsConstra<strong>in</strong>t nsubset(Lvar ls)Unione e non unione:utilizzo metodo v<strong>in</strong>colo generatos.union(ls1,ls2) Constra<strong>in</strong>t union(LSet ls1,LSet ls2) s = ls1 ∪ ls2Constra<strong>in</strong>t union(Lvar ls1,Lvar ls2)Constra<strong>in</strong>t union(LSet ls1,Lvar ls2)Constra<strong>in</strong>t union(Lvar ls1,LSet ls2)s.nunion(ls1,ls2) Constra<strong>in</strong>t nunion(LSet ls1,LSet ls2) s ≠ ls1 ∪ ls2Constra<strong>in</strong>t nunion(Lvar ls1,Lvar ls2)Constra<strong>in</strong>t nunion(LSet ls1,Lvar ls2)Constra<strong>in</strong>t nunion(Lvar ls1,LSet ls2)Intersezione e non <strong>in</strong>tersezione:utilizzo metodo v<strong>in</strong>colo generatos.<strong>in</strong>ters(ls1,ls2) Constra<strong>in</strong>t <strong>in</strong>ters(LSet ls1,LSet ls2) s = ls1 ∩ ls2Constra<strong>in</strong>t <strong>in</strong>ters(Lvar ls1,Lvar ls2)Constra<strong>in</strong>t <strong>in</strong>ters(LSet ls1,Lvar ls2)Constra<strong>in</strong>t <strong>in</strong>ters(Lvar ls1,LSet ls2)s.n<strong>in</strong>ters(ls1,ls2) Constra<strong>in</strong>t n<strong>in</strong>ters(LSet ls1,LSet ls2) s ≠ ls1 ∩ ls2Constra<strong>in</strong>t n<strong>in</strong>ters(Lvar ls1,Lvar ls2)Constra<strong>in</strong>t n<strong>in</strong>ters(LSet ls1,Lvar ls2)Constra<strong>in</strong>t n<strong>in</strong>ters(Lvar ls1,LSet ls2)Differenza e non <strong>di</strong>fferenza:45


utilizzo metodo v<strong>in</strong>colo generatos.<strong>di</strong>ffer(ls1,ls2) Constra<strong>in</strong>t <strong>di</strong>ffer(LSet ls1,LSet ls2) s = ls1 \ ls2Constra<strong>in</strong>t <strong>di</strong>ffer(Lvar ls1,Lvar ls2)Constra<strong>in</strong>t <strong>di</strong>ffer(LSet ls1,Lvar ls2)Constra<strong>in</strong>t <strong>di</strong>ffer(Lvar ls1,LSet ls2)s.n<strong>di</strong>ffer(ls1,ls2) Constra<strong>in</strong>t n<strong>di</strong>ffer(LSet ls1,LSet ls2) s ≠ ls1 \ ls2Constra<strong>in</strong>t n<strong>di</strong>ffer(Lvar ls1,Lvar ls2)Constra<strong>in</strong>t n<strong>di</strong>ffer(LSet ls1,Lvar ls2)Constra<strong>in</strong>t n<strong>di</strong>ffer(Lvar ls1,LSet ls2)L’implementazione <strong>di</strong> tutti questi meto<strong>di</strong> è <strong>in</strong>variata rispetto a JSetL orig<strong>in</strong>ale.46


Capitolo 5Implementazione: la classeConcreteMutableLSetLa classe ConcreteMutableLSet implementa l’<strong>in</strong>terfaccia MutableLSet, ovverotutti i meto<strong>di</strong> <strong>di</strong> java.util.Set e <strong>di</strong> JSetL.LSet e <strong>in</strong> più implementa anchel’<strong>in</strong>terfaccia LSetProtect<strong>ed</strong>. Viene chiamata concrete perché è una classeconcreta e pertanto può istanziare oggetti, e mutable perché può cambiarel’oggetto <strong>di</strong> <strong>in</strong>vocazioneQuesta classe ere<strong>di</strong>ta gli attributi costanti delle <strong>in</strong>terfacce LSet e LSetProtect<strong>ed</strong>e <strong>in</strong> più ha al suo <strong>in</strong>terno un oggetto protetto della classe ConcreteLSet chiamatoset, che serve sia per richiamare su <strong>di</strong> esso i meto<strong>di</strong> <strong>di</strong> ConcreteLSet,sia per realizzare i meto<strong>di</strong> <strong>di</strong> java.util.Set mo<strong>di</strong>ficando l’oggetto.Ve<strong>di</strong>amo la <strong>di</strong>chiarazione della classe e del campo set.public class ConcreteMutableLSet implements MutableLSet, LSetProtect<strong>ed</strong> {protect<strong>ed</strong> ConcreteLSet set;...}L’oggetto set è <strong>di</strong>chiarato protect<strong>ed</strong>, ovvero può essere mo<strong>di</strong>ficato solo all’<strong>in</strong>ternodel package o da una eventuale sottoclasse <strong>di</strong>retta <strong>di</strong> ConcreteMutableLSet.47


5.1 CostruttoriIn generale i costruttori della classe ConcreteMutableLSet sono gli stessidella classe ConcreteLSet (tutti quelli public). Viene richiamato ilcostruttore corrispondente <strong>di</strong> ConcreteLSet attraverso l’oggetto set:public ConcreteMutableLset(tipo t1,...) {}set = new ConcreteLSet(t1,...);È stata fatta una mo<strong>di</strong>fica al costruttore senza parametri <strong>ed</strong> è statoaggiunto un altro costruttore. In JSetL, quando viene creato un oggetto conil costruttore senza parametriLSet s = new ConcreteLSet();l’<strong>in</strong>sieme s è non <strong>in</strong>izializzato, <strong>in</strong>vece nella semantica <strong>di</strong> java.util.Setl’oggetto creato è vuoto, ovvero il metodo isEmpty ritorna true. Per farequesto il costruttore senza parametri <strong>di</strong> ConcreteMutableLSet è stato implementatocostruendo un <strong>in</strong>sieme <strong>in</strong>izializzato, ma senza elementi:public ConcreteMutableLSet() {}set = MutableLSet.empty;In questo modo set è un <strong>in</strong>sieme vuoto. Però, per non perdere la semanticadel costruttore senza parametri <strong>di</strong> JSetL, è stato implementato un nuovocostruttore (vi è anche il costruttore corrispondente con <strong>in</strong> più una str<strong>in</strong>gacome parametro per il nome):public ConcreteMutableLSet(boolean <strong>in</strong>iz) {if (<strong>in</strong>iz) set = MutableLSet.empty;else set = new ConcreteLSet();}48


public ConcreteMutableLSet(Str<strong>in</strong>g n, boolean <strong>in</strong>iz) {this(<strong>in</strong>iz);setName(n);}Il primo costruttore prende come parametro un booleano e se gli viene passatotrue crea un <strong>in</strong>sieme vuoto; altrimenti richiama il costruttore senzaparametri <strong>di</strong> ConcreteLSet che crea un oggetto non <strong>in</strong>izializzato. Il secondocostruttore richiama il primo con this(<strong>in</strong>iz) e imposta il nome a n. Adesempio:MutableLSet s1 = new ConcreteMutableLset(false);MutableLSet s2 = new ConcreteMutableLset("s2",false);s1 e s2 sono due <strong><strong>in</strong>siemi</strong> non <strong>in</strong>izializzati e hanno la stessa semantica delleistruzioni:LSet s1 = new ConcreteLSet();LSet s2 = new ConcreteLSet("s2");Se si vuole creare un <strong>in</strong>sieme illimitato bisogna utilizzare questo costruttore:MutableLSet s1 = new ConcreteMutableLSet("s1",false);MutableLSet s2 = new ConcreteMutableLSet("s2",s1.<strong>in</strong>s(1));s2.output();/** s2 = {1|s1}*/Se <strong>in</strong>vece si vuole creare un <strong>in</strong>sieme vuoto basta utilizzare il costruttoresenza parametri.49


5.2 Implementazione dei meto<strong>di</strong> <strong>di</strong> LSet e <strong>di</strong> LSetProtect<strong>ed</strong>Tutti i meto<strong>di</strong> <strong>di</strong> LSet e <strong>di</strong> LSetProtect<strong>ed</strong> vengono implementati richiamandoi meto<strong>di</strong> <strong>di</strong> ConcreteLSet attraverso l’oggetto set. La forma generale èla seguente:public tipoRitorno funzione(Param p) {return set.fuzione(p);}In questo modo vengono re<strong>in</strong><strong>di</strong>rizzati alla classe ConcreteLSet che ligestisce.Ve<strong>di</strong>amo ad esempio il metodo <strong>in</strong>s:public LSet <strong>in</strong>s(LSet s) {return set.<strong>in</strong>s(s);}In questo modo, nel momento <strong>in</strong> cui un oggetto <strong>di</strong> tipo MutableLSet utilizzail metodo <strong>in</strong>s:MutableLSet s = new ConcreteMutableLSet("s",MutableLSet.empty.<strong>in</strong>s(1).<strong>in</strong>s(3));s.output();/** s = {3,1}*/nell’implementazione viene richiamato il metodo <strong>in</strong>s <strong>di</strong> ConcreteLSet attraversol’oggetto set.5.3 Implementazione dei meto<strong>di</strong> <strong>di</strong> java.util.SetAbbiamo già visto i meto<strong>di</strong> più importanti <strong>di</strong> java.util.Set e le lorofunzioni nel paragrafo 2.3, ora ve<strong>di</strong>amo come vengono implementati nella50


classe ConcreteMutableLSet. Come <strong>in</strong> parte specificato, alcuni meto<strong>di</strong> <strong>di</strong>java.util.Set rappresentano delle <strong>operazioni</strong> <strong><strong>in</strong>siemi</strong>stiche, fornite anch<strong>ed</strong>all’<strong>in</strong>terfaccia LSet. Nella seguente tabella possiamo v<strong>ed</strong>ere le corrispondenze:java.util.Set OPERAZIONI INSIEMISTICHE LSetadd <strong>in</strong>serimento <strong>in</strong>saddAll unione unionconta<strong>in</strong>s appartenenza <strong>in</strong>conta<strong>in</strong>sAll <strong>in</strong>clusione subsetremove estrazione lessremoveAll <strong>di</strong>fferenza <strong>di</strong>fferreta<strong>in</strong>sAll <strong>in</strong>tersezione <strong>in</strong>tersequals uguaglianza eqLa <strong>di</strong>fferenza fondamentale tra i meto<strong>di</strong> implementati da java.util.Sete quelli <strong><strong>in</strong>siemi</strong>stici <strong>di</strong> LSet è che i meto<strong>di</strong> <strong>di</strong> java.util.Set mo<strong>di</strong>ficanol’oggetto chiamante, <strong>tramite</strong> un assegnamento; <strong>in</strong>vece i meto<strong>di</strong> <strong>di</strong> LSetnon mo<strong>di</strong>ficano l’oggetto, ma ne fanno una copia. Ne segue che i meto<strong>di</strong><strong>di</strong> java.util.Set non sono utilizzabili nell’ambito della programmazione<strong>di</strong>chiarativa, <strong>in</strong>vece quelli <strong>di</strong> LSet sono adatti.Inoltre vi sono altri meto<strong>di</strong> <strong>di</strong> JSetL che hanno un’analogia con quelli <strong>di</strong>java.util.Set, e sono:LSetsizeisEmptyclearconcatsubjava.util.SetsizeisEmptyclearaddAllremove51


I primi tre meto<strong>di</strong>, oltre ad avere lo stesso nome, hanno anche la stessasemantica, qu<strong>in</strong><strong>di</strong> i meto<strong>di</strong> <strong>di</strong> java.util.Set vengono implementati richiamandoil metodo omonimo <strong>di</strong> ConcreteLSet. Il metodo concat concatenadue <strong><strong>in</strong>siemi</strong>, funzione fornita anche dal metodo addAll, che può sostituirlo.Lo stesso vale per il metodo sub che rimuove un elemento, così come remove.I meto<strong>di</strong> <strong>di</strong> java.util.Set sono stati implementati solo per gli <strong><strong>in</strong>siemi</strong>limitati e <strong>in</strong>izializzati, pertanto, all’<strong>in</strong>izio <strong>di</strong> ogni metodo, viene fatto uncontrollo sull’<strong>in</strong>sieme attraverso il metodo booleano isBound() e se ritornafalse viene lanciata l’eccezione Unbound<strong>ed</strong>SetException.Ve<strong>di</strong>amo più nel particolare come sono stati implementati i meto<strong>di</strong> <strong>di</strong> java.util.Set.5.3.1 Inserimento e unione: add e addAllInserimentoIl metodo add <strong>in</strong>serisce nell’<strong>in</strong>sieme un Object.public boolean add(Object o) {if(isBound()) {<strong>in</strong>t n = set.size();set = set.<strong>in</strong>s(o);return (set.size() > n);}else throw new Unbound<strong>ed</strong>SetException();}Il metodo add prima <strong>di</strong> tutto verifica che l’<strong>in</strong>sieme sia limitato e <strong>in</strong>izializzato,altrimenti lancia l’eccezione Unbound<strong>ed</strong>SetException. Se l’<strong>in</strong>sieme è limitato,viene memorizzata la <strong>di</strong>mensione dell’<strong>in</strong>sieme nella variabile n, l’oggettoviene poi <strong>in</strong>serito attraverso il metodo <strong>in</strong>s e <strong>in</strong>f<strong>in</strong>e viene controllato se la<strong>di</strong>mensione è aumentata. Restituisce true se la <strong>di</strong>mensione è cambiata equ<strong>in</strong><strong>di</strong> è stato aggiunto l’oggetto, altrimenti ritorna false.Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo del metodo add:52


# Inserimento <strong>di</strong> oggetti e <strong>di</strong> variabili logiche <strong>in</strong>izializzate (e non) <strong>in</strong> un<strong>in</strong>sieme completamente specificato:Lvar x = new Lvar("x",3);Object[] s_elems = {1,2,x};MutableLSet s = new ConcreteMutableLSet("s",s_elems);s.output();Lvar y = new Lvar("y",5);Lvar z = new Lvar("z");s.add(y);s.add(z);s.add(4);s.output();/* OUTPUT:* s = {1,2,3}* s = {4,5,_z,1,2,3}*/L’<strong>in</strong>sieme s contiene gli <strong>in</strong>teri 1 e 2 e la variabile logica x <strong>in</strong>izializzataa 3 e con il metodo add viene aggiunta un’altra variabile logica <strong>in</strong>izializzata(y), una non <strong>in</strong>izializzata (z) e un <strong>in</strong>tero che mo<strong>di</strong>fica l’<strong>in</strong>siemes.# Inserimento <strong>di</strong> oggetti e <strong>di</strong> variabili logiche <strong>in</strong>izializzate (e non) <strong>in</strong> un<strong>in</strong>sieme non completamente specificato:Lvar x = new Lvar("x");MutableLSet s =new ConcreteMutableLSet("s",MutableLSet.empty.<strong>in</strong>s(x)); // s = {_x}s.output();s.add(1);Lvar y = new Lvar("y",2);53


s.add(y);Lvar z = new Lvar("z");s.add(z);s.output();/* OUTPUT:* s = {_x}* s = {_z,2,1,_x}*/L’<strong>in</strong>sieme s contiene la variabile logica non <strong>in</strong>izializzata x, ovvero nonè completamente specificato. Il metodo add aggiunge ad s l’<strong>in</strong>tero 1 <strong>ed</strong>ue variabili logiche, una <strong>in</strong>izializzata (y) e una no (z).# Inserimento <strong>di</strong> elementi <strong>in</strong> un <strong>in</strong>sieme illimitato o non <strong>in</strong>izializzato:MutableLSet s = new ConcreteMutableLSet("s",false);MutableLSet s2 = new ConcreteMutableLSet("s2",s.<strong>in</strong>s(2));s2.output();s2.add(3);/* OUTPUT:* s2 = {2|s}* Exception <strong>in</strong> thread "ma<strong>in</strong>" JSetL.Unbound<strong>ed</strong>SetException*/Viene lanciata l’eccezione Unbound<strong>ed</strong>SetException perché l’<strong>in</strong>sieme sè illimitato.UnioneIl metodo addAll <strong>in</strong>serisce nell’<strong>in</strong>sieme tutti gli elementi della collezione. Inquesto modo implementa l’unione tra l’oggetto <strong>di</strong> <strong>in</strong>vocazione e la collezionepassata come parametro:54


public boolean addAll(Collection c) {if(set.isBound()) {if (c <strong>in</strong>stanceof LSet) {ConcreteMutableLSet tmp = new ConcreteMutableLSet(false);boolean result =solver.boolSolve(tmp.union(((ConcreteMutableLSet) c),set));set = tmp.set;return result;}else {Iterator it = c.iterator();boolean result = true;while (it.hasNext())result = result && add(it.next());return result;}}else throw new Unbound<strong>ed</strong>SetException();}Questo m<strong>ed</strong>oto funziona solo per <strong><strong>in</strong>siemi</strong> limitati e <strong>in</strong>izializzati e si può<strong>di</strong>videre <strong>in</strong> due parti:1. la prima implementa l’unione nel caso <strong>in</strong> cui la collezione passatacome parametro sia un LSet: viene creato un oggetto temporaneo tmpdella classe stessa non <strong>in</strong>izializzato, che prende il valore dell’unionetra l’oggetto <strong>di</strong> <strong>in</strong>vocazione e la collezione passata come parametro.Questo risultato viene poi assegnato all’attributo set dell’oggetto chiamante,mo<strong>di</strong>ficandolo. Inf<strong>in</strong>e viene restituito il valore ottenuto dalmetodo boolSolve, richiamato dall’oggetto solver della classe SolverClass,che ritorna true se la union è andata a buon f<strong>in</strong>e, false altrimenti.2. la seconda implementa l’unione tra un LSet e una qualsiasi collezione:55


viene utilizzato l’iteratore della collezione per scorrere tutti gli elementie aggiungerli uno per uno all’<strong>in</strong>sieme attraverso il metodo add.Restituisce true se l’<strong>in</strong>sieme ha cambiato <strong>di</strong>mensione, false altrimenti.Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo del metodo addAll:# Unione <strong>di</strong> due <strong><strong>in</strong>siemi</strong> non completamente specificati:Lvar x1 = new Lvar("x",3);Lvar x2 = new Lvar("x2");Object[] s1_elems = {1,2,x1,x2};MutableLSet s1 = new ConcreteMutableLSet("s1",s1_elems);s1.output();Lvar y1 = new Lvar("y1",5);Lvar y2 = new Lvar("y2");Object[] s2_elems = {4,y1,y2};MutableLSet s2 = new ConcreteMutableLSet("s2",s2_elems);s2.output();s2.addAll(s1);s2.output();/* OUTPUT:* s1 = {1,2,3,_x2}* s2 = {4,5,_y2}* s2 = {1,2,3,_x2,4,5,_y2}*/Gli <strong><strong>in</strong>siemi</strong> s1 e s2 contengono variabili logiche non <strong>in</strong>izializzate e ilmetodo addAll aggiunge tutti gli elementi <strong>di</strong> s1 a s2.# Unione <strong>di</strong> due <strong><strong>in</strong>siemi</strong> <strong>di</strong> cui l’oggetto <strong>di</strong> <strong>in</strong>vocazione è non <strong>in</strong>izializzato://s1 come nell’esempio prec<strong>ed</strong>ente, s1 = {1,2,3,_x2}56


MutableLSet s2 = new ConcreteMutableLSet(false);s2.addAll(s1);/* OUTPUT:* Exception <strong>in</strong> thread "ma<strong>in</strong>" JSetL.Unbound<strong>ed</strong>SetException*/Se l’oggetto <strong>di</strong> <strong>in</strong>vocazione, <strong>in</strong> questo caso s2, non è <strong>in</strong>izializzato, vienelanciata l’eccezione Unbound<strong>ed</strong>SetException. Si noti che il metodoaddAll non fa controlli sull’oggetto passato per parametro, qu<strong>in</strong><strong>di</strong> senell’esempio prec<strong>ed</strong>ente s1 fosse illimitato e s2 specificato, il risultato<strong>di</strong> s2.addAll(s1) sarebbe true e s2 <strong>di</strong>venterebbe illimitato.# Unione <strong>di</strong> un <strong>in</strong>sieme con una collezione, ad esempio con un oggettodella classe Vector:Vector v = new Vector();for(<strong>in</strong>t i = 1; i < 5; i++)v.add(i); // v = [1,2,3,4]Lvar x = new Lvar("x",7);Lvar y = new Lvar("y");Object[] s_elems = {10,x,y};MutableLSet s = new ConcreteMutableLSet("s",s_elems);s.addAll(v);s.output();/* OUTPUT:* s = {4,3,2,1,10,7,_y}*/In questo esempio si v<strong>ed</strong>e che si può fare l’unione anche tra un <strong>in</strong>sieme,s, e un oggetto <strong>di</strong> una qualsiasi classe concreta che implemental’<strong>in</strong>teraccia Collection, ad esempio un vettore.57


5.3.2 Appartenenza e <strong>in</strong>clusione: conta<strong>in</strong>s e conta<strong>in</strong>sAllAppartenenzaIl metodo conta<strong>in</strong>s verifica se l’<strong>in</strong>sieme contiene (almeno) un elementouguale all’oggetto passato come parametro.public boolean conta<strong>in</strong>s(Object o) {if (set.isBound()) {Lvar lv = new Lvar(o);return solver.boolSolve(lv.<strong>in</strong>(this.set));}else throw new Unbound<strong>ed</strong>SetException();}Il metodo conta<strong>in</strong>s ritorna true se l’<strong>in</strong>sieme contiene l’oggetto o, falsealtrimenti. In questo metodo si controlla se l’<strong>in</strong>sieme è limitato e <strong>in</strong>izializzato:se isBound ritorna true viene costruita una variabile logica a cui vien<strong>ed</strong>ato il valore dell’oggetto o e viene restituito il valore booleano dato dallaboolSolve, che risolve il v<strong>in</strong>colo <strong><strong>in</strong>siemi</strong>stico <strong>in</strong>; se isBound ritorna falseviene lanciata l’eccezione Unbound<strong>ed</strong>SetException.Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo del metodo conta<strong>in</strong>s:# Appartenenza <strong>di</strong> un elemento ad un <strong>in</strong>sieme non completamente specificato:Lvar x = new Lvar("x");Object[] s_elems = {1,x};MutableLSet s = new ConcreteMutableLSet("s",s_elems);System.out.pr<strong>in</strong>tln("s.conta<strong>in</strong>s(2): " + s.conta<strong>in</strong>s(2));s.output();x.output();/* OUTPUT:58


* s.conta<strong>in</strong>s(2): true* s = {1,2}* x = 2*/L’<strong>in</strong>sieme s è formato dall’elemento 1 e dalla variabile logica non <strong>in</strong>izializzatax. Il metodo conta<strong>in</strong>s lega il valore 2 alla variabile logicax non <strong>in</strong>izializzata e ritorna true.# Appartenenza <strong>di</strong> un elemento ad un <strong>in</strong>sieme non <strong>in</strong>izializzato:MutableLSet s1 = new ConcreteMutableLSet(false);System.out.pr<strong>in</strong>tln("s1.conta<strong>in</strong>s(1): " + s1.conta<strong>in</strong>s(1));/* OUTPUT:* s1 = {1|LSet_0}* Exception <strong>in</strong> thread "ma<strong>in</strong>" JSetL.Unbound<strong>ed</strong>SetException*/L’<strong>in</strong>sieme s1 è illimitato, pertanto il metodo conta<strong>in</strong>s lancia l’eccezione.Lo stesso succ<strong>ed</strong>e con un <strong>in</strong>sieme non <strong>in</strong>izializzato.InclusioneIl metodo conta<strong>in</strong>sAll verifica se questa lista contiene tutti gli elementicontenuti nella collezione c. In questo modo implementa l’<strong>in</strong>clusionenell’<strong>in</strong>sieme della collezione passata come parametro:public boolean conta<strong>in</strong>sAll(Collection c) {if (set.isBound()) {if (c <strong>in</strong>stanceof LSet)return solver.boolSolve(((ConcreteMutableLSet) c).subset(set));else {boolean result = true;59


}Iterator it = c.iterator();while (it.hasNext())result = result && conta<strong>in</strong>s(it.next());return result;}}else throw new Unbound<strong>ed</strong>SetException();Anche il metodo conta<strong>in</strong>sAll controlla se l’<strong>in</strong>sieme è limitato e <strong>in</strong>izializzatoe <strong>in</strong> caso contrario lancia un’eccezione. Se <strong>in</strong>vece l’<strong>in</strong>sieme è limitato ilmetodo si può <strong>di</strong>videre <strong>in</strong> due parti come addAll: la prima parte risolve ilv<strong>in</strong>colo dell’<strong>in</strong>clusione (subset) se la collezione passata come parametro èun LSet, la seconda itera gli elementi della collezione e per ognuno <strong>di</strong> essirichiama la conta<strong>in</strong>s. Ritorna true se l’<strong>in</strong>sieme contiene tutti gli oggettidella collezione, false altrimenti.Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo del metodo conta<strong>in</strong>sAll:# Inclusione <strong>di</strong> un <strong>in</strong>sieme contenente variabili logiche <strong>in</strong>izializzate:Lvar x = new Lvar("x",4);Lvar y = new Lvar("y",6);Object[] c1_elems = {2,x,6};Object[] c2_elems = {2,4,y,8,10};MutableLSet c1 = new ConcreteMutableLSet("c1",c1_elems);MutableLSet c2 = new ConcreteMutableLSet("c2",c2_elems);c1.output();c2.output();System.out.pr<strong>in</strong>tln("c2.conta<strong>in</strong>sAll(c1): " + c2.conta<strong>in</strong>sAll(c1));/* OUTPUT:* c1 = {2,4,6}* c2 = {2,4,6,8,10}60


* c2.conta<strong>in</strong>sAll(c1): true*/L’<strong>in</strong>sieme c1 contiene (oltre a dei numeri <strong>in</strong>teri) la variabile logica x<strong>in</strong>izializziata a 4 e l’<strong>in</strong>sieme c2 contiente la variabile logica y <strong>in</strong>izializzataa 6. Quando viene richiamato il metodo conta<strong>in</strong>sAll su c2,viene verificato che l’<strong>in</strong>sieme è limitato e ritorna true, <strong>in</strong> quanto c1 è<strong>in</strong>cluso <strong>in</strong> c2.# Inclusione <strong>di</strong> una collezione <strong>in</strong> un <strong>in</strong>sieme parzialmente specificato:Vector v = new Vector();v.add(1);v.add(2);Lvar y = new Lvar("y");Object[] c1_elems = {y,2,4,6};MutableLSet c1 = new ConcreteMutableLSet("c1",c1_elems);System.out.pr<strong>in</strong>tln("v: " + v);c1.output();System.out.pr<strong>in</strong>tln("c1.conta<strong>in</strong>sAll(v): " + c1.conta<strong>in</strong>sAll(v));y.output();/* OUTPUT:* v: [1, 2]* c1 = {_y,2,4,6}* c1.conta<strong>in</strong>sAll(v): true* y = 1*/L’<strong>in</strong>sieme c1 contiene una variabile logica non <strong>in</strong>izializzata. Tramite ilmetodo conta<strong>in</strong>sAll gli viene legato il valore 1 e il metodo restituiscetrue.61


5.3.3 Estrazione e <strong>di</strong>fferenza: remove e removeAllEstrazioneIl metodo remove rimuove dall’<strong>in</strong>sieme l’oggetto passato come parametro,se presente.public boolean remove(Object o) {<strong>in</strong>t n = set.size();if (set.isBound()) {ConcreteMutableLSet tmp = new ConcreteMutableLSet(false);Lvar lv = new Lvar(o);try {boolean result = solver.boolSolve(set.less(lv,(tmp)));if (result == true)set = tmp.set;return result;}catch(Failure f) {System.out.pr<strong>in</strong>tln("Failure catturata");}return (set.size() < n);}else throw new Unbound<strong>ed</strong>SetException();}Il metodo ritorna true se la <strong>di</strong>mensione dell’<strong>in</strong>sieme è cambiata dopo l’<strong>in</strong>vocazion<strong>ed</strong>el metodo, false altrimenti. Anche questo metodo funziona solocon <strong><strong>in</strong>siemi</strong> limitati e <strong>in</strong>izializzati. Viene creato un oggetto temporaneo tmpnon <strong>in</strong>izializzato <strong>di</strong> classe ConcreteMutableLSet e una variabile logica con ilvalore dell’oggetto o passato come parametro. Il metodo less viene chiamatonel blocco try <strong>in</strong> quanto nella sua <strong>di</strong>chiarazione viene lanciata l’eccezioneFailure e deve essere catturata. Dopo la chiamata al metodo less, se ilvalore della variabile è presente nell’<strong>in</strong>sieme set, l’oggetto tmp contiene tutti62


gli elementi dell’<strong>in</strong>sieme eccetto l’elemento o. Se la boolSolve ritorna true,a set viene assegnato il valore del campo set <strong>di</strong> tmp e viene restituito ilrisultato.Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo del metodo remove:# Rimozione <strong>di</strong> un elemento da un <strong>in</strong>sieme contenente variabili logiche<strong>in</strong>izializzate:Lvar x = new Lvar("x");Lvar y = new Lvar("y",5);Object[] s_elems = {1,y,x,3,4};MutableLSet s = new ConcreteMutableLSet("s",s_elems);s.output();System.out.pr<strong>in</strong>tln("s.remove(2): " + s.remove(2));s.output();System.out.pr<strong>in</strong>tln("s.remove(y): " + s.remove(y));s.output();System.out.pr<strong>in</strong>tln("s.remove(5): " + s.remove(5));s.output();x.output();/* OUTPUT:* s = {1,5,_x,3,4}* s.remove(2): true* s = {1,5,3,4}* s.remove(y): true* s = {1,3,4}* s.remove(5): false* s = {1,3,4}* x = 2*/L’<strong>in</strong>sieme s non è completamente specificato <strong>in</strong> quanto contiene la63


variabile x non <strong>in</strong>izializzata. Inoltre contiene anche una varibile logicay <strong>in</strong>izializzata a 5. La prima volta che si chiama il metodo removesi vuole elim<strong>in</strong>are l’elemento 2 che non è presente nell’<strong>in</strong>sieme, qu<strong>in</strong><strong>di</strong>viene legato alla variabile logica x che viene elim<strong>in</strong>ata. Poi removeviene richiamato per togliere y, <strong>in</strong>fatti l’<strong>in</strong>sieme viene privato dell’elemento5, valore a cui la variabile era legata. Inf<strong>in</strong>e, tentando <strong>di</strong> togliereancora il valore 5, il metodo ritorna false, però l’elemento non esiste.DifferenzaIl metodo removeAll rimuove dall’<strong>in</strong>sieme tutti gli elementi contenuti nellacollezione c. In questo modo implementa la <strong>di</strong>fferenza tra l’<strong>in</strong>sieme e lacollezione passata come parametro:public boolean removeAll(Collection c) {if (set.isBound()) {if (c <strong>in</strong>stanceof LSet) {ConcreteMutableLSet tmp = new ConcreteMutableLSet(false);boolean result =solver.boolSolve(tmp.set.<strong>di</strong>ffer(set,(ConcreteMutableLSet) c));if (result == true)set = tmp.set;return result;}else {<strong>in</strong>t n = set.size();boolean result = false;Iterator it = c.iterator();while (it.hasNext()) remove(it.next());return (set.size() < n);}}else throw new Unbound<strong>ed</strong>SetException();64


}Il metodo removeAll rimuove tutti gli elementi della collezione passata comeparametro: ritorna true se è cambiata la <strong>di</strong>mensione dell’<strong>in</strong>sieme, ovvero seè stato tolto almeno un elemento. Se la collezione è un LSet viene utilizzatoil metodo <strong>di</strong>ffer, altrimenti si itera la collezione e si richiama il metodoremove per togliere ogni elemento.Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo del metodo removeAll:# Rimozione <strong>di</strong> un <strong>in</strong>sieme da un <strong>in</strong>sieme contenente variabili logiche<strong>in</strong>izializzate:Lvar x = new Lvar("x",2);Object[] c1_elems = {1,x,3,4};MutableLSet c1 = new ConcreteMutableLSet("c1",c1_elems);Lvar y = new Lvar("y",5);c1.output();Object[] c2_elems = {1,y};MutableLSet c2 = new ConcreteMutableLSet("c2",c2_elems);c2.output();System.out.pr<strong>in</strong>tln("c1.removeAll(c2): " + c1.removeAll(c2));c1.output();/* OUTPUT:* c1 = {1,2,3,4}* c2 = {1,5}* c1.removeAll(c2): true* c1 = {2,3,4}*/L’<strong>in</strong>sieme c1 contiene la variabile logica x <strong>in</strong>izializzata a 2 e l’<strong>in</strong>siemec2 contiente la variabile logica y <strong>in</strong>izializzata a 5. Quando vienerichiamato il metodo removeAll su c2, viene verificato che l’<strong>in</strong>sieme65


è limitato e ritorna true, <strong>in</strong> quanto è stato elim<strong>in</strong>ato l’elemento 1. S<strong>in</strong>oti che non devono essere necessariamente rimossi tutti gli elementiaff<strong>in</strong>chè il risultato sia true.# Rimozione <strong>di</strong> una collezione da un <strong>in</strong>sieme:Vector v = new Vector();v.add(2);v.add(4);System.out.pr<strong>in</strong>tln("v: " + v);Lvar x = new Lvar("x",2);Object[] c1_elems = {1,x,3,4};MutableLSet c1 = new ConcreteMutableLSet("c1",c1_elems);c1.output();System.out.pr<strong>in</strong>tln("c1.removeAll(v): " + c1.removeAll(v));c1.output();/* OUTPUT:* v = [2,4]* c1 = {1,2,3,4}* c1.removeAll(v): true* c1 = {1,3}*/Il vettore v <strong>di</strong> elementi 2 e 4 viene rimosso dall’<strong>in</strong>sieme c1.5.3.4 Intersezione: reta<strong>in</strong>AllIl metodo reta<strong>in</strong>All rimuove dall’<strong>in</strong>sieme tutti gli elementi che non sonocontenuti nella collezione c. In questo modo implementa l’<strong>in</strong>tersezione tral’<strong>in</strong>sieme e la collezione passata come parametro:public boolean reta<strong>in</strong>All(Collection c) {66


if(set.isEmptySL() && c.isEmpty()) return false;if (set.isBound()) {if (c <strong>in</strong>stanceof LSet) {ConcreteMutableLSet tmp = new ConcreteMutableLSet(false);boolean result =solver.boolSolve(tmp.<strong>in</strong>ters(set,(ConcreteMutableLSet) c));if (result == true)set = tmp.set;return result;}else {Iterator it = c.iterator();ConcreteMutableLSet tmp = new ConcreteMutableLSet();while (it.hasNext()) {Object tmpob = it.next();if (conta<strong>in</strong>s(tmpob))tmp.add(tmpob);}set = tmp.set;return true;}}else throw new Unbound<strong>ed</strong>SetException();}Questo metodo ritorna false quando sia l’oggetto d’<strong>in</strong>vocazione che lacollezione passata come parametro sono vuoti. Altrimenti controlla chel’<strong>in</strong>sieme sia limitato e <strong>in</strong>izializzato e se la collezione è un LSet utilizzail metodo <strong>in</strong>ters; per ogni altra collezione crea un iteratore e un oggetto <strong>di</strong>classe ConcreteMutableLSet temporaneo <strong>in</strong> cui vengono <strong>in</strong>seriti gli elementi<strong>in</strong> comune tra l’oggetto <strong>di</strong> <strong>in</strong>vocazione e la collezione. Inf<strong>in</strong>e l’attributoset <strong>di</strong> tmp viene copiato nel campo set dell’oggetto chiamante.67


Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo del metodo reta<strong>in</strong>All:# Intersezione non vuota tra due <strong><strong>in</strong>siemi</strong> completamente specificati:Lvar x = new Lvar("x",5);Object[] s1_elems = {1,2,x};MutableLSet s1 = new ConcreteMutableLSet("s1",s1_elems);Lvar y = new Lvar("y",2);Object[] s2_elems = {1,3,y};MutableLSet s2 = new ConcreteMutableLSet("s2",s2_elems);s1.output();s2.output();System.out.pr<strong>in</strong>tln("s1.reta<strong>in</strong>All(s2): " + s1.reta<strong>in</strong>All(s2));s1.output();/* OUTPUT:* s1 = {1,2,5}* s2 = {1,3,2}* s1.reta<strong>in</strong>All(s2): true* s1 = {1,2}*/I due <strong><strong>in</strong>siemi</strong> s1 e s2 hanno elementi <strong>in</strong> comune, qu<strong>in</strong><strong>di</strong> il metodoreta<strong>in</strong>All restutuisce true. Se entrambi gli <strong><strong>in</strong>siemi</strong> fossero vuoti, ilmetodo restituirebbe false.# Intersezione tra due <strong><strong>in</strong>siemi</strong> <strong>di</strong> cui uno non completamente specificato:Lvar x = new Lvar("x");Object[] s1_elems = {1,2,x};MutableLSet s1 = new ConcreteMutableLSet("s1",s1_elems);Lvar y = new Lvar("y",2);Object[] s2_elems = {1,3,y};MutableLSet s2 = new ConcreteMutableLSet("s2",s2_elems);68


s1.output();s2.output();System.out.pr<strong>in</strong>tln("s1.reta<strong>in</strong>All(s2): " + s1.reta<strong>in</strong>All(s2));s1.output();x.output();/* OUTPUT:* s1 = {1,2,_x}* s2 = {1,3,2}* s1.reta<strong>in</strong>All(s2): true* s1 = {1,2}* x = unknown*/L’<strong>in</strong>sieme s1, su cui è richiamato il metodo reta<strong>in</strong>All, contiene unavariabile logica non <strong>in</strong>izializzata che non viene legata a nessun valore.Dopo la chiamata al metodo, s1 contiene l’<strong>in</strong>tersezione degli element<strong>in</strong>oti.# Intersezione con un <strong>in</strong>sieme non <strong>in</strong>izializzato:Lvar x = new Lvar("x",5);Object[] s1_elems = {1,2,x};MutableLSet s1 = new ConcreteMutableLSet("s1",s1_elems);MutableLSet s2 = new ConcreteMutableLSet(false);System.out.pr<strong>in</strong>tln("s1.reta<strong>in</strong>All(s2): " + s1.reta<strong>in</strong>All(s2));/* OUTPUT:* Exception <strong>in</strong> thread "ma<strong>in</strong>" JSetL.Unbound<strong>ed</strong>SetException*/In questo caso s1, oggetto <strong>di</strong> <strong>in</strong>vocazione, è non <strong>in</strong>izializzato, qu<strong>in</strong><strong>di</strong>viene lanciata l’eccezione Unbound<strong>ed</strong>SetException.69


# Intersezione tra un <strong>in</strong>sieme e una collezione:Vector v = new Vector();v.add(5);v.add(3);v.add(2);System.out.pr<strong>in</strong>tln("v: " + v);Lvar y = new Lvar("y",7);Object[] s_elems = {1,3,5,y};MutableLSet s = new ConcreteMutableLSet("s",s_elems);s.output();System.out.pr<strong>in</strong>tln("s.reta<strong>in</strong>All(v): " + s.reta<strong>in</strong>All(v));s.output();/* OUTPUT:* v: [5, 3, 2]* s = {1,3,5,7}* s.reta<strong>in</strong>All(v): true* s = {3,5}*/Dopo la chiamata al metodo reta<strong>in</strong>All, l’<strong>in</strong>sieme s contiene gli e-lementi <strong>in</strong> comune (l’<strong>in</strong>tersersezione) tra l’<strong>in</strong>sieme stesso e il vettorev.5.3.5 Uguaglianza: equalsBisogna porre particolare attenzione al metodo equals, <strong>in</strong> quanto esistesia nell’<strong>in</strong>terfaccia LSet che nell’iterfaccia java.util.Set, con la <strong>di</strong>fferenzache il primo prende come parametro un LSet, mentre il secondo prende unObject. Nella classe ConcreteMutableLSet vengono implementati entrambi,ovvero viene fatto l’overloa<strong>di</strong>ng del metodo equals: quando l’oggettopassato come parametro è un LSet viene richiamato il metodo equals(LSet70


s), <strong>in</strong> tutti gli altri casi viene richiamato il metodo equals(Object o).Ve<strong>di</strong>amo l’implementazione del metodo equals <strong>di</strong> LSet:public boolean equals(LSet s) {if(set.isBound())return solver.boolSolve(set.eq(s));else throw new Unbound<strong>ed</strong>SetException();}Questo metodo viene chiamato solo quando il parametro passato è un LSet:si controlla che l’<strong>in</strong>sieme sia limitato e <strong>in</strong>izializzato e si risolve il v<strong>in</strong>colo eq.Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo del metodo equals(LSet s):# Equivalenza tra <strong><strong>in</strong>siemi</strong> <strong>di</strong> MutableLSet:Lvar x = new Lvar("x");Object[] s1_elems = {x,2,3};MutableLSet s1 = new ConcreteMutableLSet("s1",s1_elems);Lvar y = new Lvar("y",3);Object[] s2_elems = {2,1,y};MutableLSet s2 = new ConcreteMutableLSet("s2",s2_elems);s1.output();s2.output();System.out.pr<strong>in</strong>tln("s1.equals(s2): " + s1.equals(s2));x.output();MutableLSet s3 =new ConcreteMutableLSet("s3",MutableLSet.empty.<strong>in</strong>s(1).<strong>in</strong>s(y));s3.output();System.out.pr<strong>in</strong>tln("s1.equals(s3): " + s1.equals(s3));/* OUTPUT:* s1 = {1,2,3}* s2 = {2,1,3}71


* s1.equals(s2): true* x = 1* s3 = {3,1}* s1.equals(s3): false*/I due <strong><strong>in</strong>siemi</strong> s1 e s2 contengono rispettivamente la variabile logicax non <strong>in</strong>izializzata e y <strong>in</strong>izializzata a 3. Il metodo equals lega lavariabile x a 1 e <strong>in</strong> questo modo i due <strong><strong>in</strong>siemi</strong> sono uguali. Inveceviene restituito false per gli <strong><strong>in</strong>siemi</strong> s1 e s3.Più generale è <strong>in</strong>vece il metodo equals(Object o) <strong>in</strong> quanto può confrontarel’<strong>in</strong>sieme LSet con un qualsiasi <strong>in</strong>sieme <strong>di</strong> java.util.Set.public boolean equals(Object o) {if (!(o <strong>in</strong>stanceof Set))return false;Collection c = (Collection) o;if (c.size() != size())return false;return conta<strong>in</strong>sAll(c);}Se l’oggetto non è un Set, allora ritorna false; altrimenti l’oggetto o vienetrasformato <strong>in</strong> una Collection: se la <strong>di</strong>mensione della collezione è <strong>di</strong>versada quella dell’oggetto <strong>di</strong> <strong>in</strong>vocazione ritorna false, altrimenti restituisce ilvalore del metodo conta<strong>in</strong>sAll.Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo del metodo equals(Object o):# Equivalenza tra <strong><strong>in</strong>siemi</strong> <strong>di</strong> MutableLSet e <strong>di</strong> java.util.Set:// s1 come nell’esempio prec<strong>ed</strong>ente (con x = 1)// s3 come nell’esempio prec<strong>ed</strong>entes1.output();72


s3.output();HashSet hset = new HashSet();hset.addAll(s1);System.out.pr<strong>in</strong>tln("hset: " + hset);System.out.pr<strong>in</strong>tln("hset.equals(s1): " + hset.equals(s1));System.out.pr<strong>in</strong>tln("s1.equals(hset): " + s1.equals(hset));System.out.pr<strong>in</strong>tln("hset.equals(s3): " + hset.equals(s3));/* OUTPUT:* s1 = {1,2,3}* s3 = {3,1}* hset: [2, 1, 3]* s.equals(s1): true* s1.equals(s): true* hset.equals(s3): false*/Gli <strong><strong>in</strong>siemi</strong> s1 e s3 sono gli stessi dell’esempio prec<strong>ed</strong>ente, <strong>in</strong> più vienecreato un <strong>in</strong>sieme HashSet aggiungendogli tutti gli elementi <strong>di</strong> s1. Idue <strong><strong>in</strong>siemi</strong>, hset e s1 vengono confrontati sia con l’equals <strong>di</strong> HashSetche con quello <strong>di</strong> MutableLSet. In entrambi i casi i due <strong><strong>in</strong>siemi</strong> sonouguali, qu<strong>in</strong><strong>di</strong> i meto<strong>di</strong> restituiscono true. Viene poi confrontato l’<strong>in</strong>siemehset con s3 e il metodo ritorna false, <strong>in</strong> quanto i due <strong><strong>in</strong>siemi</strong>sono <strong>di</strong>versi.Si noti che questo metodo permette <strong>di</strong> poter confrontare un LSet completamentespecificato con una delle classi che implementano l’<strong>in</strong>terfacciaSet, come HashSet e TreeSet.5.3.6 iteratorIl metodo iterator restituisce un iteratore sugli elementi dell’<strong>in</strong>sieme, creandoun oggetto della classe LSetIterator.73


public Iterator iterator() {if (set.isBound()) return new LSetIterator(set);else throw new Unbound<strong>ed</strong>SetException();}Il metodo controlla che l’<strong>in</strong>sieme sia limitato e <strong>in</strong>izializzato e se lo è crea unoggetto <strong>di</strong> tipo LSetIterator, altrimenti lancia un’eccezione.La classe LSetIterator implementa l’<strong>in</strong>terfaccia Iterator, la quale forniscela <strong>di</strong>chiarazione <strong>di</strong> tre meto<strong>di</strong>: un metodo next(), che avanza l’iteratoree restituisce il valore puntato; un metodo hasNext(), che determ<strong>in</strong>ase tutti gli elementi dell’<strong>in</strong>sieme sono stati visitati ritornando un valorebooleano; e può opzionalmente supportare un metodo remove(), che togli<strong>ed</strong>all’<strong>in</strong>sieme l’elemento visitato per ultimo. Nella classe LSetIteratorevengono implementati solo i primi due meto<strong>di</strong>.public class LSetIterator implements Iterator {private LSet set;private <strong>in</strong>t n = 0;public LSetIterator(LSet s) {set = s;set = set.normalizeSet();}public Object next() {Object ob = set.get(n++);if(ob <strong>in</strong>stanceof Lvar && ((Lvar)ob).<strong>in</strong>iz))ob = ((Lvar)ob).val;return ob;}public boolean hasNext() {return (n < set.size());}74


}public void remove() {}La classe LSetIterator ha due attributi: un oggetto LSet (set) e un <strong>in</strong>tero(n) che viene <strong>in</strong>crementato per scorrere gli elementi. Il costruttoreprende come parametro un LSet che assegna al proprio attributo e su <strong>di</strong>esso richiama il metodo normalizeSet per togliere evenutali elementi duplicatimemorizzati nell’<strong>in</strong>sieme. Il metodo next memorizza <strong>in</strong> un oggetto obl’elemento successivo dell’<strong>in</strong>sieme richiamando il metodo get(n++) sull’attributoset; viene controllato se l’oggetto ob è un’istanza della classe Lvare se è <strong>in</strong>izializzato, <strong>in</strong> tal caso viene memorizzato solo il suo valore; <strong>in</strong>f<strong>in</strong>esi restituisce ob. Il metodo hasNext restituisce un booleano, <strong>in</strong> particolareritorna true se n è m<strong>in</strong>ore della <strong>di</strong>mensione dell’<strong>in</strong>sieme, false altrimenti.Il metodo remove non viene implementato.Il seguente esempio mostra un semplice uso degli iteratori:# Iterazione <strong>di</strong> un <strong>in</strong>sieme non completamente noto:Lvar x = new Lvar("x");Lvar y = new Lvar("y",4);Object[] ob_elems = {2,3,x,y};MutableLSet s = new ConcreteMutableLSet(ob_elems);Iterator it = s.iterator();while (it.hasNext())System.out.pr<strong>in</strong>tln(it.next());/* OUTPUT:* 4* Lvar: x, id: 0, is NOT <strong>in</strong>itializ<strong>ed</strong>.* 3* 2*/75


Viene creata una variabile logica non <strong>in</strong>izializzata x e una variabile ycon valore 4. Viene poi costruito un array <strong>di</strong> oggetti ob elems formatodagli <strong>in</strong>teri 2 e 3 e dalle varibili logiche x e y. L’<strong>in</strong>sieme s viene<strong>in</strong>zializzato con il valore <strong>di</strong> ob elems; con l’istruzione Iterator it =s.iterator() viene costruito un iteratore <strong>di</strong> s. Il ciclo while stampatutti gli oggetti dell’<strong>in</strong>sieme: f<strong>in</strong>ché esiste un elemento successivo(it.hasNext == true), avanza al successivo e lo stampa.Appena dopo essere stato creato, un iteratore punta a un valore specialeche prec<strong>ed</strong>e il primo elemento, cosicché il primo elemento si ottiene con laprima chiamata a next().5.3.7 sizeIl metodo size resituisce la <strong>di</strong>mensione dell’<strong>in</strong>sieme, solo se questo è limitato,altrimenti lancia una eccezione.public <strong>in</strong>t size() {if(set.isBound())return set.size();else throw new Unbound<strong>ed</strong>SetException();}Il metodo size controlla che l’<strong>in</strong>sieme sia limitato e <strong>in</strong>izializzato con il metodoisBound e <strong>in</strong> tal caso richiama il metodo size dell’attributo set, altrimentilancia un’eccezione.Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo del metodo size:# Dimensione <strong>di</strong> un <strong>in</strong>sieme:MutableLSet s1 = new ConcreteMutableLSet("s1");s1.output();System.out.pr<strong>in</strong>tln("s1.size(): " + s1.size());s1.add(1);76


Lvar x = new Lvar("x",3);s1.add(x);s1.output();System.out.pr<strong>in</strong>tln("s1.size(): " + s1.size());Lvar y = new Lvar("y");s1.add(y);s1.output();System.out.pr<strong>in</strong>tln("s1.size(): " + s1.size());MutableLSet s2 = new ConcreteMutableLSet(false);s2.size();/* OUTPUT:* emptySet = {}* s1.size(): 0* s1 = {3,1}* s1.size(): 2* s1 = {_y,3,1}* s1.size(): 3* Exception <strong>in</strong> thread "ma<strong>in</strong>" JSetL.Unbound<strong>ed</strong>SetException*/L’<strong>in</strong>sieme s1 viene creato vuoto, qu<strong>in</strong><strong>di</strong> la size restituisce il valore0. Dopo vengono <strong>in</strong>seriti nell’<strong>in</strong>sieme una variabile <strong>in</strong>izializzata e un<strong>in</strong>tero, qu<strong>in</strong><strong>di</strong> la <strong>di</strong>mensione dell’<strong>in</strong>sieme <strong>di</strong>venta 2. Inf<strong>in</strong>e si <strong>in</strong>serisceuna variabile logica non <strong>in</strong>izializzata e la size restituisce il valore 3.Con un <strong>in</strong>sieme non <strong>in</strong>izializzato o illimitato, il metodo size lancial’eccezione Unbound<strong>ed</strong>SetException.5.3.8 isEmptyIl metodo isEmpty verifica se l’<strong>in</strong>sieme è vuoto.public boolean isEmpty() {77


}return set.isEmpty();Questo metodo semplicemente richiama il metodo omonimo sull’attributoset.Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo del metodo isEmpty:# Controllo se un <strong>in</strong>sieme è vuoto:MutableLSet s1 = new ConcreteMutableLSet("s1");s1.output();System.out.pr<strong>in</strong>tln("s1.isEmpty(): " + s1.isEmpty());Lvar x = new Lvar("x",3);s1.add(x);s1.output();System.out.pr<strong>in</strong>tln("s1.isEmpty(): " + s1.isEmpty());/* OUTPUT:* emptySet = {}* s1.isEmpty(): true* s1 = {3}* s1.isEmpty(): false*/L’<strong>in</strong>sieme s1 nel momento <strong>in</strong> cui viene creato è vuoto, viene poi aggiuntauna variabile logica <strong>in</strong>izializzata e il metodo isEmpty ritornafalse.5.3.9 clearIl metodo clear rimuove dall’<strong>in</strong>sieme tutti gli elementi.public void clear() {set = ConcreteLSet.empty;}78


Il metodo clear pone set uguale all’<strong>in</strong>sieme vuoto.Ve<strong>di</strong>amo qualche esempio <strong>di</strong> utilizzo del metodo clear:# Rimozione <strong>di</strong> tutti gli elementi da un <strong>in</strong>sieme:Lvar x = new Lvar("x");Lvar y = new Lvar("y",3);MutableLSet s1 =new ConcreteMutableLSet(MutableLSet.empty.<strong>in</strong>s(1).<strong>in</strong>s(x).<strong>in</strong>s(y));s1.output();s1.clear();s1.output();/* OUTPUT:* LSet_3 = {3,_x,1}* emptySet = {}*/L’<strong>in</strong>sieme s1 viene creato con l’<strong>in</strong>tero 1, la variabile logica x <strong>in</strong>izializzataa 0 e la varibile logica y non <strong>in</strong>izializzata. Dopo l’utilizzo delmetodo clear, l’<strong>in</strong>sieme è vuoto.79


Capitolo 6EsempiIn questo capitolo si vuole mostrare come l’<strong>in</strong>terfaccia MutableLSet e laclasse ConcreteMutableLSet, che la implementa, possano essere usate sfruttandoi meto<strong>di</strong> <strong>di</strong> LSet, <strong>di</strong> java.util.Set e anche <strong>in</strong> modo ibrido, cioèutilizzando meto<strong>di</strong> <strong>di</strong> entrambe le <strong>in</strong>terfacce nella stessa applicazione. Perfar questo ve<strong>di</strong>amo tre programmi che utilizzano l’<strong>in</strong>terfaccia MutableLSete la classe ConcreteMutableLSet: due che utilizzano separatamente i meto<strong>di</strong>delle due <strong>in</strong>terfacce LSet e java.util.Set; uno che utilizza meto<strong>di</strong> <strong>di</strong>entrambe le <strong>in</strong>terfacce.6.1 Utilizzo degli <strong><strong>in</strong>siemi</strong> <strong>di</strong> JSetLCome primo esempio ve<strong>di</strong>amo un programma <strong>in</strong> cui si usano gli <strong><strong>in</strong>siemi</strong> e lerelative operazione previste <strong>in</strong> JSetL.6.1.1 La classe Color<strong>in</strong>gData una mappa <strong>di</strong> n regioni R 1 , . . . , R n e un <strong>in</strong>sieme <strong>di</strong> m colori c 1 , . . . , c m ,il problema consiste nel trovare un assegnamento <strong>di</strong> colori per le regioni dellamappa tale che le regioni vic<strong>in</strong>e abbiano colori <strong>di</strong>fferenti.La classe Color<strong>in</strong>g ha un metodo color<strong>in</strong>g che prende come parametri tre<strong><strong>in</strong>siemi</strong> chiamati reg (regioni), map (mappa) e col (colori).80


public static void color<strong>in</strong>g(MutableLSet reg, MutableLSet map, MutableLSet col)throws Failure {Lvar Y = new Lvar();Solver.add(reg.eq(col));Solver.forall(Y, col, MutableLSet.empty.<strong>in</strong>s(Y).n<strong>in</strong>(map));Solver.solve();return;}Nel metodo viene viene creata una variabile logica Y non <strong>in</strong>izializzata,viene aggiunto al constra<strong>in</strong>t store il v<strong>in</strong>colo che i colori e le regioni devonoessere uguali (attraverso il metodo eq), <strong>tramite</strong> il metodo forall della classeSolverClass si <strong>in</strong>troduce il v<strong>in</strong>colo che per ogni elemento Y appartenenteall’<strong>in</strong>sieme dei colori, Y non appartenga (n<strong>in</strong>) a map. Inf<strong>in</strong>e viene chiamatala solve per risolvere tutti i v<strong>in</strong>coli.Un possibile ma<strong>in</strong> che utilizza il metodo color<strong>in</strong>g è il seguente:public static void ma<strong>in</strong> (Str<strong>in</strong>g[] args) throws Failure {Lvar R1 = new Lvar("R1");Lvar R2 = new Lvar("R2");Lvar R3 = new Lvar("R3");Lvar[] n1 = {R1,R2};Lvar[] n2 = {R2,R3};Lvar[] regions = {R1,R2,R3};Str<strong>in</strong>g[] colors = {"r<strong>ed</strong>", "blue"};MutableLSet m1 = new ConcreteMutableLSet(n1);MutableLSet m2 = new ConcreteMutableLSet(n2);MutableLSet Regions = new ConcreteMutableLSet(regions);MutableLSet Colors = new ConcreteMutableLSet(colors);MutableLSet Map =new ConcreteMutableLSet("Map", MutableLSet.empty.<strong>in</strong>s(m2).<strong>in</strong>s(m1));color<strong>in</strong>g(Regions, Map, Colors);81


R1.output();R2.output();R3.output();Map.output();Nel ma<strong>in</strong> viene creato l’<strong>in</strong>sieme Regions che contiene un array <strong>di</strong> tre variabililogiche non <strong>in</strong>izializzate (Regions = {R 1 , R 2 , R 3 }), viene costruito l’<strong>in</strong>siemeMap che a sua volta contiene due <strong><strong>in</strong>siemi</strong> (Map = {{R 1 , R 2 }, {R 2 , R 3 }}), vienecreato l’<strong>in</strong>sieme Colors <strong>tramite</strong> un array <strong>di</strong> Str<strong>in</strong>g (Colors = { ′′ r<strong>ed</strong> ′′ , ′′ blue ′′ }.A questo punto viene richiamato il metodo color<strong>in</strong>g sui tre <strong><strong>in</strong>siemi</strong> creatie viene stampata una possibile soluzione, ad esempio:R1 = r<strong>ed</strong>R2 = blueR3 = r<strong>ed</strong>Map = {{r<strong>ed</strong>,blue},{blue,r<strong>ed</strong>}}6.1.2 Le mo<strong>di</strong>fiche a Color<strong>in</strong>gNella classe Color<strong>in</strong>g sono state fatte alcune mo<strong>di</strong>fiche riguardanti gli <strong><strong>in</strong>siemi</strong>:non viene più usata la classe Set orig<strong>in</strong>ale <strong>di</strong> JSetL, ma vengono utilizzatel’<strong>in</strong>terfaccia MutableLSet e la classe ConcreteMutableLSet. Ve<strong>di</strong>amo<strong>in</strong> particolare quali mo<strong>di</strong>fiche sono state fatte:- Nel metodo color<strong>in</strong>g gli <strong><strong>in</strong>siemi</strong> passati come parametro vengonomo<strong>di</strong>ficati da Set a MutableLSet. In generale <strong>in</strong> tutti i meto<strong>di</strong> cheprendono come parametro un <strong>in</strong>sieme si deve fare questa mo<strong>di</strong>fica;- Il terzo parametro del metodo forall non è più Set.empty.<strong>in</strong>s(x).n<strong>in</strong>(map),ma MutableLSet.empty.<strong>in</strong>s(x).n<strong>in</strong>(map). Ogni volta che si trova lavariabile statica empty bisogna mo<strong>di</strong>ficare da Set a MutableLSet;- Nel ma<strong>in</strong> tutti gli <strong><strong>in</strong>siemi</strong> orig<strong>in</strong>ariamente creati nel seguente modoSet s = new Set(parametri);82


vengono cosi mo<strong>di</strong>ficati:MutableLSet s = new ConcreteMutableLSet(parametri);6.2 Utilizzo degli <strong><strong>in</strong>siemi</strong> <strong>di</strong> java.util.SetCome esempio ve<strong>di</strong>amo un algoritmo che, dato un <strong>in</strong>sieme <strong>di</strong> numeri <strong>in</strong>teri,restituisce l’elemento con valore massimo, utilizzando solo i meto<strong>di</strong>dell’<strong>in</strong>terfaccia java.util.Set.6.2.1 La classe MaxLa classe Max calcola il massimo <strong>di</strong> un <strong>in</strong>sieme <strong>di</strong> <strong>in</strong>teri, attraverso il propriometodo maxInt.public static <strong>in</strong>t maxInt(MutableLSet s) {<strong>in</strong>t max = 0;if(s.isEmpty()) return 0;else{Iterator it = s.iterator();while (it.hasNext()) {Object ob = it.next();if(ob <strong>in</strong>stanceof Integer)if((Integer)ob > max)max = (Integer)ob;}return max;}}Il metodo maxInt prende come parametro un MutableLSet e restituisce un<strong>in</strong>tero. Al suo <strong>in</strong>terno crea una variabile <strong>in</strong>tera max che <strong>in</strong>izializza a 0.Se l’<strong>in</strong>sieme è vuoto, allora ritorna il valore 0; altrimenti crea un iteratoree confronta ogni elemento dell’<strong>in</strong>sieme con la variabile max: se l’elemento83


confrontato è maggiore, allora a max viene assegnato il suo valore. Inf<strong>in</strong>esi restituisce la variabile max. Nel ciclo while viene fatto un cast esplicito,<strong>in</strong> quanto il metodo next dell’iteratore restituisce un Object, ma su questonon è possibile fare confronti.Ve<strong>di</strong>amo ora il ma<strong>in</strong> <strong>in</strong> cui viene costruito l’<strong>in</strong>sieme:public static void ma<strong>in</strong> (Str<strong>in</strong>g[] args) {MutableLSet s = new ConcreteMutableLSet();<strong>in</strong>t[] a = {1,6,4,8,10,5};for(<strong>in</strong>t i = 0; i < a.length; i++)s.add(a[i]);System.out.pr<strong>in</strong>t("Max = " + maxInt(s));}L’<strong>in</strong>sieme s viene creato con l’<strong>in</strong>terfaccia MutableLSet e la classe concretaConcreteMutableLSet. Viene poi costruito un array <strong>di</strong> <strong>in</strong>teri, che viene<strong>in</strong>serito nell’<strong>in</strong>sieme s scorrendo gli elemento dell’array con un ciclo for eaggiungendo ad s ogni elemento con il metodo add. Inf<strong>in</strong>e viene stampato ilrisultato richiamando il metodo maxInt sull’<strong>in</strong>sieme s e il cui risultato è 0.In questo semplice esempio si può notare che l’utilizzo dei meto<strong>di</strong> isEmpty,iterator e add <strong>di</strong> ConcreteMutableLSet ha la stessa s<strong>in</strong>tassi e semanticarichiesta dall’<strong>in</strong>terfaccia java.util.Set.Si noti, <strong>in</strong>oltre, che la m<strong>ed</strong>esima <strong>di</strong>chiarazione del metodo maxInt può essereutilizzata anche per un’implementazione <strong>di</strong>chiarativa, senza dover mo<strong>di</strong>ficarenulla nel programma chiamante e viceversa.6.3 Un esempio ibridoVe<strong>di</strong>amo un esempio <strong>in</strong> cui si utilizzano sia meto<strong>di</strong> <strong>di</strong> java.util.Set chemeto<strong>di</strong> <strong>di</strong> LSet, ovvero degli <strong><strong>in</strong>siemi</strong> <strong>di</strong> JSetL orig<strong>in</strong>ale.La classe Sum calcola la somma degli elementi <strong>di</strong> un <strong>in</strong>sieme, attraversoil proprio metodo sum.84


SolverClass Solver = new SolverClass();public static void sum(MutableLSet s, Lvar sSum) throws Failure {if(s.isEmpty()) Solver.add(sSum.eq(0));else{Iterator it = s.iterator();<strong>in</strong>t sumElem = 0;while (it.hasNext()) {Object ob = it.next();if(ob <strong>in</strong>stanceof Integer)sumElem += (Integer)ob;}Solver.add(sSum.eq(sumElem));}Solver.solve();}Il metodo sum prende come parametri un MutableLSet s, che contiene l’<strong>in</strong>sieme<strong>di</strong> cui si fa la somma degli elementi, e un Lvar sSum, <strong>in</strong> cui viene memorizzatala somma. Se l’<strong>in</strong>sieme è vuoto, viene aggiunto nel constra<strong>in</strong>t storeil v<strong>in</strong>colo che la variabile logica sSum vale 0 (sSum.equ(0)), <strong>tramite</strong> l’oggettoSolver della classe SolverClass. Altrimenti, se l’<strong>in</strong>sieme non è vuoto, vienecreato un iteratore dell’<strong>in</strong>sieme e una variabile <strong>in</strong>tera sumElem <strong>in</strong>izializzata a0. Nel ciclo while vengono iterati gli elementi dell’<strong>in</strong>sieme e, attraverso uncast a Integer dell’oggetto restituito dal metodo next dell’iteratore, vienememorizzato e sommato ogni valore nella variabile sumElem. Fuori dal cicloviene aggiunto al constra<strong>in</strong>t store il v<strong>in</strong>colo che la variabile sSum sia ugualeal valore <strong>di</strong> sumElem. Inf<strong>in</strong>e viene chiamata la solve sull’oggetto Solver.In sum si v<strong>ed</strong>e come vengono <strong>in</strong>tegrati i meto<strong>di</strong> dell’<strong>in</strong>terfaccia java.util.Setcon i meto<strong>di</strong> della libreria JSetL: della prima si utilizzano gli iteratori perscorrere l’<strong>in</strong>sieme, della seconda si utilizzano i v<strong>in</strong>coli e la loro risoluzione<strong>tramite</strong> il metodo solve.Ve<strong>di</strong>amo il ma<strong>in</strong>, dove viene costruito l’<strong>in</strong>sieme:85


public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args) throws Failure {Lvar a = new Lvar(6);Lvar x = new Lvar("sum");Object[] ob = {4,3,2,5,a};MutableLSet S = new ConcreteMutableLSet("S",ob); // S = {4,3,2,5,6}sum(S,x);S.output();x.output();}Vengono create due variabile logiche: a, <strong>in</strong>izializzata con valore 6 e cheviene poi <strong>in</strong>serita tra gli elementi dell’<strong>in</strong>sieme; x, non <strong>in</strong>izializzata, a cuiviene dato il nome “sum” e che conterrà la somma degli elementi. Viene poicreato un array <strong>di</strong> Object, ob, (si noti che non è un array <strong>di</strong> <strong>in</strong>teri, <strong>in</strong> quantosi è voluto generalizzare l’esempio <strong>in</strong>serendo nell’<strong>in</strong>sieme anche una variabilelogica <strong>in</strong>izializzata) e un <strong>in</strong>sieme S della classe ConcreteMutableLSet, <strong>in</strong>izializzatocon gli elementi <strong>di</strong> ob e con nome “S”. Viene chiamato il metodosum con parametri S e x e <strong>in</strong>f<strong>in</strong>e viene stampato l’<strong>in</strong>sieme e la somma deisuoi elementi:// OUTPUT:S = {4,3,2,5,6}sum = 2086


Capitolo 7Conclusioni e lavori futuriÈ stata creata un’unica astrazione <strong>di</strong> <strong>in</strong>sieme su cui poter operare sia coni meto<strong>di</strong> forniti da java.util.Set che con quelli <strong>di</strong> JSetL, limitando alm<strong>in</strong>imo le mo<strong>di</strong>fiche al package JSetL. Il nuovo package JSetL forniscequ<strong>in</strong><strong>di</strong> anche tutte le funzionalità degli <strong><strong>in</strong>siemi</strong> <strong>di</strong> <strong>Java</strong>, mantenendo la pienacompatibilità con applicazioni scritte usando le prec<strong>ed</strong>enti librerie (a meno<strong>di</strong> nomi).In futuro si può migliorare l’efficienza creando una nuova classe cheimplementa l’<strong>in</strong>terfaccia MutableLSet e che al suo <strong>in</strong>terno utilizza, oltreall’oggetto <strong>di</strong> classe ConcreteLSet, un oggetto della classe HashSet, perrichiamare i meto<strong>di</strong> dell’<strong>in</strong>terfaccia java.util.Set quando l’<strong>in</strong>sieme è completamentespecificato.Inoltre, si potrebbe <strong>in</strong>tegrare la classe Lst <strong>di</strong> JSetL e l’<strong>in</strong>terfaccia java.util.List<strong>in</strong> modo analogo a quanto fatto per gli <strong><strong>in</strong>siemi</strong>.87


Bibliografia[1] Gianfranco Rossi, Elio Panegai, Elisabetta Poleo.JSetL: A <strong>Java</strong> Library for Support<strong>in</strong>g Declarative Programm<strong>in</strong>g <strong>in</strong> <strong>Java</strong>.Software-Practice & Experience, 37, 2007, p 115-149.[2] Elio Panegai, Elisabetta Poleo, Gianfranco Rossi.JSetL User’s Manual. Version 1.0. Novembre 2004.[3] Harvey M. Deitel, Paul J. Deitel.<strong>Java</strong>, Fondamenti <strong>di</strong> programmazione. Apogeo, 2003.[4] J. Jaffer, M. J. Maher.Constra<strong>in</strong>t Logic Programm<strong>in</strong>g: a Survey.In Journal Logic Programm<strong>in</strong>g 19, 20: 503 - 581, 1994.[5] Agost<strong>in</strong>o Dovier, Carla Piazza, Enrico Pontelli, Gianfranco Rossi.Set and Constra<strong>in</strong>t Logic Programm<strong>in</strong>g.ACM Toplas, 22(5) 2000, 861-931.[6] http://java.sun.com/j2se/1.5.0/docs/api/.88

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!