LIP: 1 Marzo 2005
Classe Object e Vettori
Partiamo da
• L’esercizio dell’ultima esercitazione
realizzato tramite array
• Vedremo come si puo’ fare in modo piu’
efficiente usando un nuovo tipo di dato
(Vector)
Classe Object
• La classe Object è la superclasse, diretta o indiretta, di
ciascuna classe in Java, quindi Object è supertipo di
qualsiasi tipo (che definisce oggetti).
• Grazie al meccanismo dell'ereditarietà

i suoi metodi sono ereditati da tutti i tipi (che
definiscono oggetti).

ad una variabile di tipo Object possiamo assegnare
oggetti di qualsiasi tipo (principio di sostituzione)
Attenzione
• I tipi primitivi int, boolean, double non sono
sottotipi di Object, non sono oggetti (vedi la differenza
nella semantica di FP)
• String, Integer sono esempi di tipi primitivi
sottotipi di Object
• Abbonato, Elenco sono esempi di tipi non primitivi
sottotipi di Object
Metodi Eredidati da Object
•Sono metodi ereditati da tutti i sottotipi
•I metodi più utili sono:
{
\\EFFECTS: restituisce una rappresentazione
dell'oggetto this in forma di stringa. }
public String toString()
public boolean equals(Object obj)
\\EFFECTS :verifica se l'oggetto this è uguale a obj.
Commenti a toString()
•La definizione del metodo nella classe Object restituisce una stringa che contiene
il nome della classe dell'oggetto su cui il metodo è invocato ed una
rappresentazione esadecimale del codice hash dell'oggetto (indirizzo in memoria dell'oggetto).
•Questo accade perché la classe Object non può conoscere la struttura dell'oggetto.
•Il metodo ereditato e’ poco utile.
•Il metodo deve quindi essere sovrascritto in ogni classe che lo usa per ottenere un risultato significativo.
Tipicamente, di un oggetto si vogliono mostrare (nella stringa restituita) i valori delle
variabili d'istanza o comunque una informazione significativa che descriva lo stato interno
Commenti ad
equals
•Concettualmente, l'invocazione
<obj1>.equals(<obj2>)
del metodo equals dovrebbe restituire true quando il contenuto
dei due oggetti è uguale (non il riferimento, come per l'operatore ==).
•L'esempio tipico è il confronto tra stringhe.
•D’altra parte il metodo equals della classe Object, e’ implementato
non potendo fare alcuna assunzione sulla struttura interna degli
oggetti su cui viene invocato (utilizza semplicemente l'operatore == per confrontarli.)
•Deve quindi essere sovrascritto in modo opportuno nel sottotipo (overriding)
a seconda delle caretteristiche degli oggetti
•Per il tipo String il metodo e’ gia’ ridefinito in modo primitivo
Metodo equals
•Notiamo che il parametro del metodo equals ha tipo Object
•Lo possiamo chiamare su oggetti di ogni tipo (come String ) proprio grazie
al principio di sostituzione
•Il confronto con == va bene solo per testare se un oggetto ha riferimento null
Tipo
Vector
• La classe java.util.Vector definisce degli oggetti,
chiamati vettori (Vector), che consentono di rappresentare
sequenze di oggetti di lunghezza variabile.
• Simili agli array a parte il fatto che
-la dimensione di un vettore può variare durante
l'esecuzione di un programma
- non vanno creati per un tipo prefissato, le posizioni del
Vector hanno un tipo generico Object
-quindi possono contenere oggetti di ogni tipo anche tra
loro disomogenei (tipo String o Integer)
Costruttori e Metodi (alcuni)
public Vector (){
\\EFFECTS: crea un vettore vuoto}
• Notate che a differenza che per gli arrays non e’ necessario fissare al momento
della creazione la dimensione
• Ci sono anche altri costruttori tipo quelli degli arrays che permettono di creare
un vettore vuoto ma con una certa capacita’ (dato numero di posizioni allocate
ma vuote). Serve solo per avere implementazioni piu’ o meno efficienti (per ora
lo ignoriamo)
Metodi simili a quelli dell’array
public int size (){
\\EFFECTS: restituisce il numero di elementi presenti nel
vettore}
public Object elementAt (int index){
\\EFFECTS: restituisce l'elemento di indice index }
public void setElementAt (Object obj, int index){
\\EFFECTS:
sostituisce obj all'oggetto della posizione index}
•
Se index e’ fuori dal size del vettore viene sollevata
una eccezione come per gli arrays
Metodi per rimuovere e
aggiungere
public void insertElementAt (Object obj, int index){
\\MODIFIES:this
\\EFFECTS: inserisce obj nella posizione index e sposta tutti gli
elementi, da index in poi, di una posizione}
public void addElement (Object obj){
\\MODIFIES:this
\\EFFECTS: aggiunge una posizione alla fine che contiene obj }
public void removeElementAt (int index){
\\MODIFIES:this
\\EFFECTS: rimuove l'oggetto presente nella posizione index e sposta
all'indietro di una posizione tutti gli elementi successivi
a quello rimosso}
public boolean removeElement (Object obj){
\\MODIFIES:this
\\EFFECTS: rimuove la prima occorrenza
dell'oggetto obj se presente restituendo true,oppure
restituisce false}
Differenze con gli Arrays
• Rifate l’esercizio dell’ Elenco di abbonati usando un Vector invece di
un array
• Lo stato interno di un oggetto di tipo Elenco e’ descritto da un Vector
di Abbonato (invece che da un array)
public Vector persone; // variabile d’istanza
• Essendo Abbonato sottotipo di Object possiamo usare un Vector per
memorizzare abbonati (per esempio per aggiungere)
persone.addElement(new Abbonato(12,15))
Attenzione
•quando usiamo i metodi della classe Vector restituiscono valori di
tipo Object. Cosa succede se vogliamo leggere il nome del primo Abbonato del Vector?
// accesso alla variabile d’istanza di Abbonato che memorizza il nome
int n= persone.elementAt(1).nome;
•Il compilatore non puo’ sapere quale tipo di valori sono correntemente
memorizzati nella prima posizione del Vector, quindi guarda il tipo restituito dal metodo
•elementAt e’ un metodo che restituisce un valore di tipo Object, quindi rileva un errore
di tipo (Object non ha una variabile d’istanza nome)
Quindi
•quando usiamo i metodi della classe Vector bisogna usare cast opportuni
Abbonato a= (Abbonato) persone.elementAt(1);
a.nome…….// accesso alla variabile d’istanza (senza il cast darebbe un errore)
•In questo modo possiamo aggirare il problema della differenza tra tipo effettivo (Abbonato)
e tipo apparente (Object)
Commenti
•
Nel momento in cui cambiate l’implementazione del tipo di dato Elenco
deve essere rifatto il programma che il testing?
• Dipende da come lo avete fatto (se accedeva alla variabile d’istanza persone di
tipo array della classe Elenco ..chiaramente non va piu’ bene)
• Per esempio si poteva verificare la dimensione corrente dell’array per testare i
metodi definiti
Elenco e=new Elenco();
System.out.println(e.persone.length);
e.inserisci(12);
System.out.println(e.persone.length);
Commenti
•
•
•
•
•
•
Notiamo che il metodo di testing puo’ accedere alla variabile d’istanza persona
perche’ questa e’ public
Questo suggerisce che non e’ una buona pratica di programmazione rendere
visibili le variabili che implementano lo stato interno di un tipo di dato
Infatti se l’utente del tipo di dato (p.e. Elenco) puo’ accedere alle variabili
d’istanza che lo implementano tutto il codice diventa dipendente dalla
implementazione del tipo di dato
Quando l’implementazione del tipo di dato dovesse (come tipicamente sara’)
essere migliorata-modificata tutto il codice che la usa e che dipende
dall’implementazione dovra’ essere riscritto
Come succede in questo caso col metodo di testing
E’ fondamentale invece (come vedremo) rendere le varie parti indipendenti
dalla loro implementazione interna usando il piu’ possibile specificatori di
accesso private
Sulla implementazione di Elenco
•
•
•
Per quelli che se la sentono (tipo che hanno gia’ finito l’esercizio dell’altra
volta) potete fare una implementazione un po’ piu’ efficiente
Usando un Vector in cui gli Abbonati sono mantenuti in modo ordinato rispetto
al loro nome (come in un elenco del telefono vero)
In tale caso i metodi di ricerca, inserimento e rimozione devono essere fatti in
modo da mantenere l’ordinamento e da sfruttarlo
Per Esempio
Se gli Abbonati sono ordinati in base al nome per cercare un certo Abbonato non
dovremo sempre scorrere tutto il vettore
Classe Elenco 1
import java.util.*;
import java.io.*;
public class Elenco{
public Vector persone; // variabile d’istanza
public static int numero=1;
// costruttore
public Elenco(){
persone=new Vector();
}
}
•Lo stato interno di un oggetto di tipo Elenco e’ descritto da un Vector
persone
•Le variabili d’istanza devono essere inizializzate dal costruttore (invocato per creare
un nuovo oggetto)
•persone viene inizializzato al vettore vuoto tramite il costruttore di Vector new Vector();
•Se non creiamo il vector il riferimento rimane null non possiamo farci nulla!
Classe Elenco 2
\\metodi
public int cercanum(int s){
for (int j=0; j< persone.length;j++){
Abbonato a =(Abbonato) persone.elementAt(j);
if (a.nome==s)
{return a.num;}}
return 0;
}
public void inserisci(int s){
persone.addElement(new Abbonato(s,numero));
numero=numero+1;
}
}
•Quando leggiamo dal Vector dobbiamo fare il cast (anche se sappiamo che contiene
oggetti di tipo Abbonato, il compilatore non lo puo’ sapere).
•Il metodo addElement aggiunge in fondo al vettore (crea una nuova posizione)
•Per aggiungere un nuovo Abbonato dobbiamo fare new Abbonato() per creare il
nuovo oggetto
Sottoclasse
public class Elencoext extends Elenco{
public Elencoext(){
}
public void rimuovi(int s){
int j=0;
while (j< persone.size()){
Abbonato a= (Abbonato) persone.elementAt(j);
if (a.nome==s)
{persone.removeElementAt(j);}
else {j++;}
}
}
}
•Il metodo removeElementAt elimina una posizione (non lascia una posizione null)
Tester
public class Tester{
public static void main(String[] args){
Elenco e=new Elenco();
e.inserisci(112);
int k=e.cercanum(112);
System.out.println(k);
int h=e.cercanum(113);
System.out.println(h);
e.inserisci(113);
int t=e.cercanum(113);
System.out.println(t);
Elencoext y= new Elencoext();
y.inserisci(112);
y.inserisci(112);
int r=y.cercanum(112);
System.out.println(r);
System.out.println(y.persone.size());
y.rimuovi(112);
System.out.println(y.persone.size());
}
}
Commenti
• La gestione di dati modificabili e’ notevolmente piu’ semplice rispetto
agli arrays (automaticamente vengono aggiunte o tolte posizioni)
• Per contro bisogna fare attenzione ai sottotipi ed usare cast per
risolvere i problemi del compilatore
Scarica

int index