Finora:
Modificatori di accesso: possono impedire l'accesso (modifica/uso) delle componenti e l'invocazione dei metodi.
Si applicano a: classi, componenti e metodi.
Dicono chi può usare una certa cosa.
Finora, non abbiamo usato modificatori
Di solito, si usano solo public e private
Tipicamente: si usano sulle componenti.
class Esempio { private int x; }
Un programma non può accedere alla componente x dell'oggetto:
class Prova { public static void main(String args[]) { Esempio e; e=new Esempio(); e.x=12; System.out.println(e.x); } }
Genera due errori:
Prova.java:6: x has private access in Esempio e.x=12; ^ Prova.java:8: x has private access in Esempio System.out.println(e.x); ^ 2 errors
Se una componente è privata, si può accedere solo all'interno della classe.
Come faccio a mettere un intero in e.x?
Come faccio a vedere il valore memorizzato?
Posso accedere a this.x dentro i metodi della classe.
class Esempio { private int x; void setX(int n) { this.x=n; } int getX() { return this.x; } }
Impedisco l'accesso diretto alla componente dell'oggetto
Permetto la modifica/uso della componente attraverso i metodi.
Ogni volta che voglio memorizzare un valore in e.x, faccio e.setX(valore).
Per vedere il valore di e.x, uso e.getX()
class Prova { public static void main(String args[]) { Esempio e; e=new Esempio(); // e.x=12; e.setX(12); // System.out.println(e.x); System.out.println(e.getX()); } }
Le linee commentate davano errore.
Verifica tipica: non tutti i valori sono accettabili.
Esempio: l'età deve essere un numero positivo.
class Studente { private String nome; private int eta; private double media; void setEta(int n) { if(n>0) this.eta=n; else { System.out.println("Errore"); System.exit(1); } } int getEta() { return this.eta; } ... }
Posso decidere che, una volta costruito, l'oggetto non si può più cambiare:
class Studente { private String nome; private int eta; private double media; Studente(String nome, int eta, double media) { this.nome=nome; this.eta=eta; this.media=media; } // metodi getNome, getEta, getMedia }
Quando creo l'oggetto, posso decidere i valori delle sue componenti.
Da questo momento in poi, non si possono più modificare.
Posso vietare le modifiche solo su singoli campi, e permettere modifiche a più campi insieme:
class Studente { private String nome; private int eta; private double media; ... void setMedia(double m) { this.media=m; } void setNomeEta(String nome, int eta) { this.nome=nome; this.eta=eta; } // metodi getNome, getEta, getMedia }
In questo modo, posso cambiare nome ed eta insieme, ma non uno solo dei due.
Invece, posso cambiare media da solo.
Esempio: non posso inserire la media se non ho scritto il nome.
class Studente { private String nome; private int eta; private double media; ... void setMedia(double m) { if(this.nome!=null) this.media=m; else { System.out.println("Errore"); System.exit(1); } } ... }
Nota: gli errori in genere si gestiscono con le eccezioni.
Modificare la classe Segmento con le coordinate di un punto che è il mediano.
class Segmento { int x1; int y1; int x2; int y2; void mediano() { xm=(this.x1+this.x2)/2; ym=(this.y1+this.y2)/2; } }
Assicurarsi che il punto sia sempre il mediano fra gli altri due.
Aggiungo due campi privati
Aggiungo il metodo per metterci le coordinate del mediano.
class Segmento { int x1; int y1; int x2; int y2; private int xm; private int ym; }
I programmi non possono usare xm ed ym
Il problema è che potrei fare modifiche ad x1 senza aggiornare il centro.
Tutte le componenti sono private.
L'accesso (lettura e scrittura) avviene attraverso metodi.
class Segmento { private int x1; private int y1; private int x2; private int y2; private int xm; private int ym; int getX1() { return this.x1; } void setX1(int val) { this.x1=val; this.mediano(); } ... void mediano() { xm=(this.x1+this.x2)/2; ym=(this.y1+this.y2)/2; } }
Posso modificare le componenti solo attraverso metodi.
Nei metodi, ci posso scrivere operazioni ausiliare da fare.
Nell'esempio, ogni volta che una componente viene modificata, si calcola di nuovo il mediano.
void setX1(int val) { this.x1=val; this.mediano(); }
Senza incapsulamento, non c'era modo di obbligare chi scrive il programma a invocare il metodo mediano ogni volta che fa s.x1=qualcosa
Cosa succede se cambio i diritti di accesso in una sottoclasse?
Si può sempre fare:
class Sopra { private int y; private int getY() { return this.y; } }
class Sotto extends Sopra { public int y; public int getY() { return this.y; } }
Funziona tutto.
Si può fare con le variabili, perchè tanto sono variabili nuove (e le vecchie esistono ancora)
Non si può fare con i metodi:
class Sopra { public int x; public int getX() { return this.x; } }
class Sotto extends Sopra { private int x; // ok private int getX() { // errore! return this.x; } }
La definizione del metodo getX in Sotto dà errore.