Un'interfaccia è un contratto
Un'interfaccia dichiara cosa può fare una classe senza dire come. È un elenco di firme di metodi che ogni classe che la implementa promette di rispettare. Lo scopo è il disaccoppiamento: il codice può lavorare con il tipo dell'interfaccia senza preoccuparsi di quale classe concreta ci sia dietro.
Circle implements Shape significa che Circle deve definire area e perimeter. Una volta fatto, un Circle è una Shape e può essere memorizzato in una variabile di tipo Shape.
Tante classi, un solo tipo
La potenza si vede quando più classi non collegate tra loro implementano la stessa interfaccia. Il codice scritto per Shape le gestisce tutte:
Il ciclo non chiede mai "questo è un Circle o un Rectangle?": chiama semplicemente area() e si fida del contratto. Aggiungere un Triangle in seguito non richiede alcuna modifica qui.
Implementare più interfacce
Una classe estende una sola classe, ma può implementare un numero qualsiasi di interfacce: è così che Java ottiene in modo sicuro l'"ereditarietà multipla" del comportamento:
Elenca le interfacce separate da virgole dopo implements. La classe deve soddisfarle tutte.
Metodi default e static
Da Java 8 un'interfaccia può contenere corpi di metodo. Un metodo default dà alle classi che la implementano un'implementazione già pronta che ereditano gratis (e possono ridefinire):
I metodi default permettono a un'interfaccia di evolversi: si aggiunge un metodo senza rompere tutte le classi che già la implementano. Un metodo static di un'interfaccia, invece, è un'utilità che richiami sull'interfaccia stessa, come Comparator.naturalOrder().
Costanti
I campi di un'interfaccia sono implicitamente public static final: sono costanti, non stato di istanza:
interface Physics {
double GRAVITY = 9.81; // automatically public static final
}
Tradizionalmente le interfacce non hanno stato per oggetto; l'assenza di campi di istanza è parte di ciò che le distingue dalle classi.
Interfacce funzionali
Un'interfaccia con esattamente un metodo astratto è un'interfaccia funzionale, e puoi implementarla con una lambda expression invece di un'intera classe:
Questa è la base delle lambda di Java e dei tipi di java.util.function (Function, Predicate, Supplier e compagnia). L'annotazione @FunctionalInterface rende esplicita l'intenzione e fa sì che il compilatore imponga la regola del metodo unico.
Interfaccia o classe astratta
Entrambe ti permettono di programmare verso un'astrazione, quindi quando scegliere l'una o l'altra?
- Interfaccia: una capacità che classi non collegate tra loro possono condividere. Un
Birde unAirplanepossono essere entrambiFlyable. Una classe può implementarne molte. Nessuno stato di istanza. - Classe astratta: stato e codice condivisi tra classi strettamente correlate. Un
Cate unDogestendono entrambiAnimal, ereditando campi comuni e metodi parzialmente implementati. Una classe ne estende una sola.
Uno schema comune le combina: un'interfaccia definisce il contratto e una classe astratta implementa le parti ripetitive, così le sottoclassi concrete completano solo i dettagli specifici.
Prossimo argomento: le classi astratte
Le interfacce definiscono comportamento senza stato. Le classi astratte stanno a metà strada tra le interfacce e le classi complete: possono dichiarare metodi non implementati e avere anche campi e costruttori. È l'argomento della pagina successiva.
Domande frequenti
Cos'è un'interfaccia in Java?
Un'interfaccia è un contratto: un insieme di firme di metodi (e costanti) che una classe promette di fornire. Dice cosa può fare una classe, non come. Una classe usa la parola chiave implements per adottare un'interfaccia e deve fornire un corpo per ogni metodo astratto che l'interfaccia dichiara. Le interfacce permettono di usare in modo intercambiabile classi non collegate tra loro attraverso un tipo condiviso.
Qual è la differenza tra un'interfaccia e una classe astratta in Java?
Una classe può implementare molte interfacce ma estendere una sola classe (astratta). Tradizionalmente le interfacce non hanno stato di istanza e dichiarano solo comportamento, mentre una classe astratta può avere campi, costruttori e logica parzialmente implementata. Usa un'interfaccia per definire una capacità che più classi non collegate possono condividere; usa una classe astratta per condividere stato e codice comune tra sottoclassi strettamente correlate.
Un'interfaccia Java può avere corpi di metodo?
Sì, da Java 8. I metodi di un'interfaccia marcati default forniscono un corpo che le classi che la implementano ereditano (e possono ridefinire con l'override), e i metodi static di un'interfaccia offrono funzionalità di utilità richiamabili sull'interfaccia stessa. I normali metodi di un'interfaccia restano astratti, cioè solo una firma, e le classi che la implementano devono definirli.