Package e Controllo degli Accessi in Java
- Utilizzando i package in Java, bisogna tenere presente che le regole di visibilità e accesso sono influenzate dalla posizione delle classi nei package.
- In particolare, le classi in package differenti possono avere accesso limitato ai membri di altre classi a seconda dei modificatori di accesso utilizzati.
Package e Accesso ai Membri
Nelle lezioni precedenti, abbiamo esaminato vari aspetti del meccanismo di controllo degli accessi di Java e dei suoi modificatori di accesso.
Per esempio, sappiamo già che l'accesso a un membro private
di una classe è concesso solo agli altri membri della stessa classe.
I package aggiungono un'ulteriore dimensione al controllo degli accessi. Come vedremo, Java fornisce molti livelli di protezione per consentire un controllo fine sulla visibilità di variabili e metodi all'interno di classi, sottoclassi e package.
Le classi e i package sono entrambi strumenti per incapsulare e contenere lo spazio dei nomi e l'ambito di variabili e metodi. I package fungono da contenitori per classi e altri package subordinati. Le classi fungono da contenitori per dati e codice. La classe è la più piccola unità di astrazione di Java. Per quanto riguarda l'interazione tra classi e package, Java prevede quattro categorie di visibilità per i membri di classe:
- Sottoclassi nello stesso package
- Non-sottoclassi nello stesso package
- Sottoclassi in package differenti
- Classi che non sono né nello stesso package né sottoclassi
I tre modificatori di accesso, private
, public
e protected
, forniscono una varietà di modi per produrre i molti livelli di accesso richiesti da queste categorie. La Tabella che segue riassume le interazioni.
Categoria | private |
Nessun Modificatore | protected |
public |
---|---|---|---|---|
Stessa classe | Sì | Sì | Sì | Sì |
Sottoclasse stesso package | No | Sì | Sì | Sì |
Non-sottoclasse stesso package | No | Sì | Sì | Sì |
Sottoclasse altro package | No | No | Sì | Sì |
Non-sottoclasse altro package | No | No | No | Sì |
Anche se il meccanismo di controllo degli accessi di Java può sembrare complicato, possiamo semplificarlo come segue. Qualsiasi cosa dichiarata public
può essere acceduta da classi differenti e da package differenti. Qualsiasi cosa dichiarata private
non può essere vista al di fuori della sua classe. Quando un membro non ha una specificazione esplicita di accesso, è visibile sia alle sottoclassi sia alle altre classi nello stesso package. Questo è l'accesso predefinito. Se si vuole permettere che un elemento sia visibile al di fuori del proprio package, ma solo a classi che derivano direttamente dalla propria classe, allora bisogna dichiarare quell'elemento protected
.
La Tabella di sopra si applica solo ai membri delle classi. Una classe non annidata ha solo due possibili livelli di accesso: predefinito e public
. Quando una classe è dichiarata public
, è accessibile al di fuori del suo package. Se una classe ha accesso predefinito, allora può essere acceduta solo da altro codice all'interno dello stesso package. Quando una classe è public
, deve essere l'unica classe public
dichiarata nel file, e il file deve avere lo stesso nome della classe.
Accessibilità influenzata dai moduli
La funzionalità dei moduli può influenzare anche l'accessibilità. Vedremo i moduli nelle prossime lezioni.
Un Esempio di Accesso
Il seguente esempio mostra tutte le combinazioni dei modificatori di controllo degli accessi. Questo esempio ha due package e cinque classi. Le classi dei due package differenti devono essere salvate in directory denominate con il nome dei rispettivi package — in questo caso, p1
e p2
.
Il codice sorgente per il primo package definisce tre classi: Protezione
, Derivata
e StessoPackage
. La prima classe definisce quattro variabili int
in ciascuna delle modalità di protezione legali. La variabile n
è dichiarata con la protezione predefinita, n_pri
è private
, n_pro
è protected
e n_pub
è public
.
Ogni classe successiva in questo esempio proverà ad accedere alle variabili in un'istanza di questa classe. Le linee che non compileranno a causa di restrizioni di accesso sono commentate. Prima di ciascuna di queste linee, c'è un commento che elenca i luoghi da cui questo livello di protezione consentirebbe l'accesso.
La seconda classe, Derivata
, è una sottoclasse di Protezione
nello stesso package, p1
. Questo concede a Derivata
l'accesso a ogni variabile in Protezione
tranne che a n_pri
, quella private
.
La terza classe, StessoPackage
, non è una sottoclasse di Protezione
, ma si trova nello stesso package e ha quindi accesso a tutte tranne che a n_pri
.
Questo è il file Protezione.java
:
package p1;
public class Protezione {
int n = 1;
private int n_pri = 2;
protected int n_pro = 3;
public int n_pub = 4;
public Protezione() {
System.out.println("costruttore base");
System.out.println("n = " + n);
System.out.println("n_pri = " + n_pri);
System.out.println("n_pro = " + n_pro);
System.out.println("n_pub = " + n_pub);
}
}
Questo è il file Derivata.java
:
package p1;
class Derivata extends Protezione {
Derivata() {
System.out.println("costruttore derivato");
System.out.println("n = " + n);
// solo nella classe
// System.out.println("n_pri = " + n_pri);
System.out.println("n_pro = " + n_pro);
System.out.println("n_pub = " + n_pub);
}
}
Questo è il file StessoPackage.java
:
package p1;
class StessoPackage {
StessoPackage() {
Protezione p = new Protezione();
System.out.println("costruttore stesso package");
System.out.println("n = " + p.n);
// solo nella classe
// System.out.println("n_pri = " + p.n_pri);
System.out.println("n_pro = " + p.n_pro);
System.out.println("n_pub = " + p.n_pub);
}
}
Segue il codice sorgente per l'altro package, p2
. Le due classi definite in p2
coprono le altre due condizioni che sono influenzate dal controllo degli accessi. La prima classe, Protezione2
, è una sottoclasse di p1.Protezione
. Questo concede accesso a tutte le variabili di p1.Protezione
tranne n_pri
(perché è private
) e n
, la variabile dichiarata con la protezione predefinita. Ricordare che la protezione predefinita consente l'accesso solo all'interno della classe o del package, non a sottoclassi esterne al package. Infine, la classe AltroPackage
ha accesso solo a una variabile, n_pub
, che è stata dichiarata public
.
Questo è il file Protezione2.java
:
package p2;
class Protezione2 extends p1.Protezione {
Protezione2() {
System.out.println("costruttore derivato altro package");
// solo classe o package
// System.out.println("n = " + n);
// solo classe
// System.out.println("n_pri = " + n_pri);
System.out.println("n_pro = " + n_pro);
System.out.println("n_pub = " + n_pub);
}
}
Questo è il file AltroPackage.java
:
package p2;
class AltroPackage {
AltroPackage() {
p1.Protezione p = new p1.Protezione();
System.out.println("costruttore altro package");
// solo classe o package
// System.out.println("n = " + p.n);
// solo classe
// System.out.println("n_pri = " + p.n_pri);
// classe, sottoclasse o package
// System.out.println("n_pro = " + p.n_pro);
System.out.println("n_pub = " + p.n_pub);
}
}
Se si vogliono provare questi due package, qui ci sono due file di test che si possono usare. Quello per il package p1
è mostrato qui:
// Demo package p1.
package p1;
// Istanziare le varie classi in p1.
public class Demo {
public static void main(String[] args) {
Protezione ob1 = new Protezione();
Derivata ob2 = new Derivata();
StessoPackage ob3 = new StessoPackage();
}
}
Il file di test per p2
è mostrato di seguito:
// Demo package p2.
package p2;
// Istanziare le varie classi in p2.
public class Demo {
public static void main(String[] args) {
Protezione2 ob1 = new Protezione2();
AltroPackage ob2 = new AltroPackage();
}
}