Vai alla Home Page About me Courseware Federica Living Library Federica Federica Podstudio Virtual Campus 3D La Corte in Rete
 
Il Corso Le lezioni del Corso La Cattedra
 
Materiali di approfondimento Risorse Web Il Podcast di questa lezione

Marco Faella » 6.Classi interne, locali ed anonime


Classi interne

Java permette di definire una classe (o interfaccia) all’interno di un’altra.
Queste classi vengono chiamate “interne” o “annidate”.
Tale meccanismo arricchisce le possibilità di relazioni tra classi, introducendo in particolare nuove regole di visibilità.
Se la definizione di una classe si trova all’interno di un metodo, tale classe viene chiamata “locale”.
Infine, una classe locale può anche essere “anonima”, quando il suo nome non sarebbe rilevante e/o utile.

Visibilità delle classi interne

Oltre a campi e metodi, una classe può contenere altre classi o interfacce, dette “interne”.
Una classe che non sia interna viene chiamata “top-level”.
A differenza delle classi top-level, le classi interne possono avere tutte le quattro visibilità ammesse dal linguaggio.
La visibilità di una classe interna X stabilisce quali classi possono utilizzarla (cioè, istanziarla, estenderla, dichiarare riferimenti o parametri di tipo X, etc.).

Consideriamo il seguente esempio:

public class A {

private class B {

...

}

class C {

...

}

}

In quest’esempio, la classe B non è visibile al di fuori di A, mentre la classe C è visibile a tutte le classi che si trovano nello stesso pacchetto di A.

Visibilità delle classi interne (segue)

Dall’esterno di A, i nomi completi delle classi B e C sono A.B e A.C, rispettivamente.

La visibilità di una classe interna non ha alcun effetto sul codice che si trova all’interno della classe che la contiene.
Ad esempio, la classe B dell’esempio precedente è visibile a tutto il codice contenuto in A, compreso il codice contenuto in altre classi interne ad A, come ad esempio C.

Lo stesso discorso si applica per i campi e i metodi di una classe interna,i loro attributi di visibilità hanno effetto solo sul codice esterno alla classe contenitrice.

In altre parole, tra classi contenute nella stessa classe non vige alcuna restrizione di visibilità.

Relazione tra oggetti

Ciascun oggetto di una classe interna (non statica, come spiegato dopo) possiede un riferimento implicito ad un oggetto della classe contenitrice.
Tale riferimento viene inizializzato automaticamente al momento della creazione dell’oggetto.
Tale riferimento non può essere modificato.

Supponiamo che B sia una classe interna di A.
Se viene creato un oggetto di tipo B in un contesto non statico della classe A, il riferimento implicito verrà inizializzato con il valore corrente di this.
In tutti gli altri casi, è necessario utilizzare una nuova forma dell’operatore “new”, ovvero:
<riferimento ad oggetto di tipo A>.new B(…).

All’interno della classe B, la sintassi per denotare questo riferimento implicito è A.this.
Nei contesti statici di B, siccome non è disponibile this, non è disponibile neanche A.this.
L’uso di A.this è facoltativo, come quello di this.
Cioè, si può accedere ai campi e ai metodi della classe A anche direttamente.

Classi interne statiche

Le classi interne possono essere statiche o meno.
Una classe interna dichiarata nello scope di classe (cioè al di fuori di metodi e inizializzatori) è statica se preceduta dal modificatore “static”.
Una classe interna dichiarata all’interno di un metodo o di un inizializzatore eredita il proprio essere statica o meno dal metodo in cui è contenuta o dal campo che si sta inizializzando.

Le classi interne statiche non possiedono il riferimento implicito alla classe contenitrice.

Riassumendo, le classi interne non statiche godono delle seguenti proprietà distintive:

  • Privilegi di visibilità rispetto alla classe contenitrice e alle altre classi in essa contenute:
    • permettono una stretta collaborazione tra queste classi.
  • Restrizioni di visibilità rispetto alle classi esterne a quella contenitrice:
    • permettono di nascondere la classe all’esterno.
  • Un riferimento implicito ad un oggetto della classe contenitrice:
    • intuitivamente, ogni oggetto della classe interna “conosce” quello che della classe contenitrice che l’ha creato.

Le classi interne statiche godono solo delle prime due proprietà.

Alcuni testi si riferiscono a tutte le classi interne come “annidate” e riservano il termine “interne” solo alle classi interne non statiche.

Classi locali

Una classe interna dichiarata all’interno di un metodo viene chiamata classe locale.
Una classe locale non ha specificatore di visibilità, in quanto è visibile solo all’interno del metodo in cui è dichiarata.
Una classe locale non può avere il modificatore static, in quanto eredita il suo essere statica o meno dal metodo in cui è dichiarata.
Oltre a godere delle proprietà comuni alle classi interne, le classi locali “vedono” le variabili locali e i parametri formali del metodo in cui sono contenute, a patto che essi siano final, cioè costanti.
La slide successiva illustra questa, apparentemente arbitraria, restrizione.

Classi locali (segue)

Gli esemplari di una classe locale possono vivere più a lungo del metodo in cui la loro classe è visibile.
Tipicamente, questo succede quando un oggetto di una classe locale viene restituito dal metodo, mascherato da una superclasse o super-interfaccia nota all’esterno.

In questi casi, l’accesso alle variabili locali (compresi i parametri formali) di quel metodo può avvenire quando quel metodo è ormai terminato, cancellando di fatto quelle variabili.
Si ricordi che le variabili locali e i parametri formali sono allocati sullo stack e quindi vengono cancellati al termine di ciascuna invocazione del metodo.

Pertanto, per dare l’illusione al programmatore di accedere a quelle variabili, il compilatore in realtà inserisce negli oggetti delle classi locali delle copie di quelle variabili.

Se il meccanismo funzionasse anche per variabili non final, il “trucco” delle copie delle variabili locali diventerebbe visibile al programmatore, invece che nascosto.
Infatti, potrebbe accadere che una variabile locale viene modificata dopo la creazione di un oggetto della classe interna.
L’oggetto della classe interna, interrogato successivamente, ricorderebbe il vecchio valore di quella variabile, invece del valore modificato.

Classi anonime

Talvolta una classe interna viene utilizzata soltanto una volta, tipicamente per istanziare un oggetto che poi viene mascherato con una classe o interfaccia nota.
In questi casi, si può utilizzare una classe anonima.
Una classe anonima si definisce a partire da una classe o una interfaccia esistente.
Nella tabella in figura, a sinistra riportiamo la sintassi per la creazione di classi anonime a partire da una classe o interfaccia esistente.
A destra riportiamo il costrutto equivalente utilizzando normali classi con nome.


Classi anonime (segue)

Ad esempio, nella libreria AWT (Abstract Windowing Toolkit) per le interfacce grafiche, l’interfaccia ActionListener rappresenta un oggetto in grado di rispondere ad un evento

interface ActionListener {
void actionPerformed(ActionEvent e);
}

La seguente classe utilizza una classe anonima per restituire un oggetto di tipo ActionListener

Mostra codice

Memory layout di classi interne

La figura rappresenta il memory layout delle classi definite di seguito.

Notate in particolare la differenza tra classe interna e sottoclasse.

Mostra codice
Figura 1: Il memory layout del frammento di programma a sinistra. In particolare, sono mostrati i quattro oggetti creati dal main.

Figura 1: Il memory layout del frammento di programma a sinistra. In particolare, sono mostrati i quattro oggetti creati dal main.


Esercizio (esame 21/04/2008)

Nell’ambito di un programma di geometria, si implementi la classe Triangolo, il cui costruttore accetta le misure dei tre lati. Se tali misure non danno luogo ad un triangolo, il costruttore deve lanciare un’eccezione. Il metodo getArea restituisce l’area di questo triangolo.
Si implementino anche la classe Triangolo.Rettangolo, il cui costruttore accetta le misure dei due cateti, e la classe Triangolo.Isoscele, il cui costruttore accetta le misure della base e di uno degli altri lati.

Si ricordi che:

  • Tre numeri a, b e c possono essere i lati di un triangolo a patto che a<b+c, b<a+c e c<a+b.
  • L’area di un triangolo di lati a, b e c è data da: (formula di Erone), dove p è il semiperimetro.
Esempio d’uso (fuori dalla classe Triangolo).

Esempio d'uso (fuori dalla classe Triangolo).


  • Contenuti protetti da Creative Commons
  • Feed RSS
  • Condividi su FriendFeed
  • Condividi su Facebook
  • Segnala su Twitter
  • Condividi su LinkedIn
Progetto "Campus Virtuale" dell'Università degli Studi di Napoli Federico II, realizzato con il cofinanziamento dell'Unione europea. Asse V - Società dell'informazione - Obiettivo Operativo 5.1 e-Government ed e-Inclusion

Fatal error: Call to undefined function federicaDebug() in /usr/local/apache/htdocs/html/footer.php on line 93