Annidamento con interfacce Java

Se hai letto il mio tutorial Java 101 che introduce classi statiche e classi interne, dovresti avere familiarità con le basi per lavorare con classi nidificate nel codice Java. In questo suggerimento Java, imparerai tre modi comuni per utilizzare le tecniche di nidificazione con le interfacce Java. Dimostrerò anche brevemente le interfacce di nidificazione con metodi statici, noti anche come interfacce di metodo statico.

Ulteriori informazioni sulle interfacce Java

Per un'introduzione alle interfacce Java, inclusa la differenza tra classi e interfacce, vedere il mio tutorial Java 101 Lavorare con le interfacce in Java.

Interfacce di annidamento nelle classi

Java ti consente di dichiarare le interfacce all'interno delle classi. Una volta dichiarata, un'interfaccia diventa automaticamente un membro statico della classe. Non è necessario dichiarare l'interfaccia con la staticparola chiave. Considera il seguente esempio:

 class EnclosingClass { interface EnclosedInterface1 { } static interface EnclosedInterface2 { } } 

EnclosedInterface1e EnclosedInterface2sono interfacce membro statiche . Non esiste un equivalente alle classi locali perché le interfacce non possono essere dichiarate in blocchi. Tuttavia, le interfacce possono essere utilizzate in contesti di classi anonime.

Le interfacce annidate in genere non sono accessibili dall'esterno delle classi che le racchiudono. Altrimenti, potresti dichiararli come interfacce di primo livello . Invece, sono accessibili dall'interno delle loro classi di chiusura, come dimostrato qui:

 class EnclosingClass { interface EnclosedInterface1 { } static interface EnclosedInterface2 { } static class EnclosedClass1 implements EnclosedInterface1, EnclosedInterface2 { } class EnclosedClass2 implements EnclosedInterface1, EnclosedInterface2 { } void m() { class EnclosedClass3 implements EnclosedInterface1, EnclosedInterface2 { } new EnclosedInterface1() { }; } } 

Si noti che la classe membro statica EnclosedClass1, la classe membro non statica EnclosedClass2e la classe locale EnclosedClass3implementano entrambe le interfacce nidificate. Tuttavia, solo un'interfaccia può essere implementata in un contesto di classe anonimo. (Vedi Classi statiche e classi interne in Java per ulteriori informazioni sulle classi anonime.)

Classi con interfacce nidificate in java.net

La libreria di classi standard di Java include classi con interfacce nidificate. Ad esempio, InetAddress(nel java.netpacchetto), che rappresenta un indirizzo di protocollo Internet, dichiara un'interfaccia privata Addressesimplementata da classi membri private CachedAddressese NameServiceAddressesstatiche. Dichiara inoltre NameServiceun'interfaccia privata implementata da classi membri private PlatformNameServicee HostsFileNameServicestatiche.

Interfacce di annidamento nelle interfacce

Java consente anche di dichiarare le interfacce all'interno delle interfacce. In questo caso, un'interfaccia nidificata è un membro statico della sua interfaccia che lo racchiude e ancora una volta la staticparola chiave è ridondante. Inoltre, l'interfaccia nidificata è implicitamente pubblica. Ecco un esempio:

 interface EnclosingInterface { interface EnclosedInterface1 // implicitly static and public { } static interface EnclosedInterface2 // explicitly static and implicitly public { } } 

Si accede a un'interfaccia racchiusa anteponendo al suo nome il nome dell'interfaccia inclusa e l'operatore di accesso ai membri. Ad esempio, specificare EnclosingInterface.EnclosedInterface1di accedere EnclosedInterface1.

Interfacce nidificate in Java Collections Framework

Il Java Collections Framework fornisce informazioni sull'utilità di annidare un'interfaccia in un'altra. Considera l' java.util.Mapinterfaccia, che descrive una mappa (una raccolta di coppie chiave-valore). L' Mapinterfaccia astrae cosa significa essere una mappa. Classi come HashMape java.util.TreeMapimplement Map, che descrivono diversi tipi di implementazioni di mappe.

Mapdichiara Entrycome uno dei suoi membri. Entryè un'interfaccia nidificata che descrive una coppia chiave-valore. L' Entryinterfaccia è dichiarata a Mapcausa della stretta relazione tra le due interfacce: ogni voce deve appartenere a una mappa. Entryè implementato dalle java.util.AbstractMapclassi dei membri statici SimpleEntrye della SimpleImmutableEntryclasse. In genere ignorerai queste classi di membri statici e interagirai Map.Entryinvece con .

Annidamento di classi nelle interfacce

Una delle caratteristiche del linguaggio più strano di Java è la capacità di annidare una classe all'interno di un'interfaccia. Come con un'interfaccia nidificata, la classe nidificata è implicitamente pubblica e statica. Ecco un esempio:

 interface EnclosingInterface { class EnclosedClass { } } 

Nonostante la sua stranezza, essere in grado di annidare una classe all'interno di un'interfaccia può essere utile, specialmente quando c'è una stretta relazione tra l'interfaccia racchiusa e la classe racchiusa. L'acquisizione di questa relazione migliora la leggibilità del codice sorgente. Nei casi in cui la classe e l'interfaccia portano lo stesso nome, l'annidamento può anche aiutarti a evitare un conflitto di nomi tra i due.

Esempio: l'interfaccia indirizzabile racchiude la classe Address

Supponi di voler modellare entità indirizzabili come lettere, cartoline e pacchi. Ogni entità verrà descritta dalla propria classe, ma condividono tutti la comunanza di essere indirizzabili a una destinazione. Ogni classe potrebbe essere progettata con campi indirizzo duplicati oppure potresti astrarre questi dettagli in una superclasse comune. In alternativa, puoi sfruttare l' Addressableinterfaccia del listato 1 .

Listato 1. Addressable.java

 public interface Addressable { public class Address { private String boxNumber; private String street; private String city; public Address(String boxNumber, String street, String city) { this.boxNumber = boxNumber; this.street = street; this.city = city; } public String getBoxNumber() { return boxNumber; } public String getStreet() { return street; } public String getCity() { return city; } public String toString() { return boxNumber + " - " + street + " - " + city; } } public Address getAddress(); } 

L' Addressableinterfaccia descrive un'entità indirizzabile come contenente un indirizzo. Questo indirizzo è descritto dalla Addressclasse annidata . Il getAddress()metodo è implementato da qualunque classe implementa Addressable.

Il Listato 2 presenta il codice sorgente a una Letterclasse che lo implementa Addressable.

Listato 2. Letter.java

 public class Letter implements Addressable { private Addressable.Address address; public Letter(String boxNumber, String street, String city) { address = new Addressable.Address(boxNumber, street, city); } public Address getAddress() { return address; } } 

Lettermemorizza un singolo addresscampo di tipo Addressable.Address. Questa classe annidata viene istanziata dal Lettercostruttore di. Il getAddress()metodo implementato restituisce questo oggetto.

Ora considera cosa succede quando aggiungiamo classi Postcarde all'applicazione. Listato 3 presenta il codice sorgente per un'applicazione, che dimostra i , e tipi.ParcelAddressablesAddressablesPostcardParcelLetter

Listato 3. Addressables.java

 public class Addressables { public static void main(String[] args) { Addressable[] addressables = { new Letter("100", "Main Street", "Town A"), new Postcard("200", "Waterfront Drive", "Town B"), new Parcel("300", "10th Ave", "Town C") }; for (int i = 0; i < addressables.length; i++) System.out.println(addressables[i].getAddress()); } }

The main() method first creates an array of Addressable objects. It then iterates over these objects, invoking getAddress() on each object. The returned Addressable.Address object's toString() method is invoked by System.out.println() to return a string representation of the object, and this representation is subsequently output.

Compile Listings 2 and 3 along with Postcard.java and Parcel.java as follows:

 javac *.java 

Run the application as follows:

 java Addressables 

You should observe the following output:

 100 - Main Street - Town A 200 - Waterfront Drive - Town B 300 - 10th Ave - Town C 

Nested interfaces with static methods (static method interfaces)

Many developers believe that nesting a class in an interface violates object-oriented programming and the purpose for an interface. However, it's good to know about this capability because you might encounter it when maintaining someone else's code. Furthermore, now that interfaces have evolved to include default and static methods, you might encounter additional reasons to nest a class in an interface. As an example, here is a local class nested within a static method interface:

 interface I { static void m() { class C { } } } 

Conclusion

I've presented three common ways to use nesting techniques with Java classes and interfaces, and also demonstrated a controversial technique of nesting interfaces with static methods. See the complete Java 101 tutorial to learn more about nesting with static classes and inner classes in Java.

Questa storia, "Nesting with Java interfaces" è stata originariamente pubblicata da JavaWorld.