Interfacce Java spiegate con esempi

Interfacce

L'interfaccia in Java è un po 'come la classe, ma con una differenza significativa: interfacepuò avere solo firme di metodo, campi e metodi predefiniti. A partire da Java 8, puoi anche creare metodi predefiniti. Nel blocco successivo puoi vedere un esempio di interfaccia:

public interface Vehicle { public String licensePlate = ""; public float maxVel public void start(); public void stop(); default void blowHorn(){ System.out.println("Blowing horn"); } }

L'interfaccia precedente contiene due campi, due metodi e un metodo predefinito. Da solo, non è di grande utilità, ma di solito vengono utilizzati insieme alle classi. Come? Semplice, devi assicurarti di classificarlo implements.

public class Car implements Vehicle { public void start() { System.out.println("starting engine..."); } public void stop() { System.out.println("stopping engine..."); } }

Ora, c'è una regola di base : la classe deve implementare tutti i metodi nell'interfaccia. I metodi devono avere la stessa identica firma (nome, parametri ed eccezioni) come descritto nell'interfaccia. La classe non ha bisogno di dichiarare i campi, solo i metodi.

Istanze di un'interfaccia

Dopo aver creato una classe Java che implementsqualsiasi interfaccia, è possibile fare riferimento all'istanza dell'oggetto come un'istanza dell'interfaccia. Questo concetto è simile a quello di istanziazione dell'ereditarietà.

// following our previous example Vehicle tesla = new Car(); tesla.start(); // starting engine ...

Un'interfaccia non può contenere metodi di costruzione. Pertanto, non è possibile creare un'istanza di un'interfaccia stessa. È necessario creare un'istanza di una classe che implementa un'interfaccia per farvi riferimento.

Pensa alle interfacce come a un modulo di contratto vuoto o a un modello.

Cosa puoi fare con questa funzione? Polimorfismo! È possibile utilizzare solo interfacce per fare riferimento a istanze di oggetti!

class Truck implements Vehicle { public void start() { System.out.println("starting truck engine..."); } public void stop() { System.out.println("stopping truck engine..."); } } class Starter { // static method, can be called without instantiating the class public static void startEngine(Vehicle vehicle) { vehicle.start(); } } Vehicle tesla = new Car(); Vehicle tata = new Truck(); Starter.startEngine(tesla); // starting engine ... Starter.startEngine(tata); // starting truck engine ...

Ma che ne dici di più interfacce?

Sì, puoi implementare più interfacce in una singola classe. Mentre in Inheritance within Classes eri limitato a ereditare solo una classe, qui puoi estendere un numero qualsiasi di interfacce. Ma non dimenticare di implementare tutti i metodi di tutte le interfacce, altrimenti la compilazione fallirà!

public interface GPS { public void getCoordinates(); } public interface Radio { public void startRadio(); public void stopRadio(); } public class Smartphone implements GPS,Radio { public void getCoordinates() { // return some coordinates } public void startRadio() { // start Radio } public void stopRadio() { // stop Radio } }

Alcune caratteristiche delle interfacce

  • Puoi posizionare variabili all'interno di un'interfaccia, anche se non sarà una decisione sensata poiché le classi non sono vincolate ad avere la stessa variabile. In breve, evita di inserire variabili!
  • Tutte le variabili e i metodi in un'interfaccia sono pubblici, anche se si omette la publicparola chiave.
  • Un'interfaccia non può specificare l'implementazione di un particolare metodo. Sta alle classi farlo. Sebbene ci sia stata un'eccezione recente (vedi sotto).
  • Se una classe implementa più interfacce, esiste una remota possibilità che la firma del metodo si sovrapponga. Poiché Java non consente più metodi con la stessa identica firma, ciò può causare problemi. Vedi questa domanda per maggiori informazioni.

Metodi predefiniti dell'interfaccia

Prima di Java 8, non avevamo modo di indirizzare un'interfaccia in modo che avesse un'implementazione del metodo particolare. Ciò causa molta confusione e interruzioni del codice se una definizione dell'interfaccia viene modificata improvvisamente.

Supponi di aver scritto una libreria open source, che contiene un'interfaccia. Supponiamo che i tuoi clienti, ovvero praticamente tutti gli sviluppatori in tutto il mondo, lo stiano utilizzando pesantemente e siano felici. Ora è stato necessario aggiornare la libreria aggiungendo una nuova definizione di metodo all'interfaccia per supportare una nuova funzionalità. Ma ciò interromperebbe tutte le build poiché tutte le classi che implementano quell'interfaccia devono cambiare ora. Che catastrofe!

Per fortuna, Java 8 ora ci fornisce defaultmetodi per le interfacce. Un defaultmetodo può contenere la propria implementazione direttamente all'interno dell'interfaccia! Quindi, se una classe non implementa un metodo predefinito, il compilatore prenderà l'implementazione menzionata all'interno dell'interfaccia. Bello, non è vero? Quindi nella tua libreria, puoi aggiungere un numero qualsiasi di metodi predefiniti nelle interfacce senza il timore di rompere nulla!

public interface GPS { public void getCoordinates(); default public void getRoughCoordinates() { // implementation to return coordinates from rough sources // such as wifi & mobile System.out.println("Fetching rough coordinates..."); } } public interface Radio { public void startRadio(); public void stopRadio(); } public class Smartphone implements GPS,Radio { public void getCoordinates() { // return some coordinates } public void startRadio() { // start Radio } public void stopRadio() { // stop Radio } // no implementation of getRoughCoordinates() } Smartphone motoG = new Smartphone(); motog.getRoughCoordinates(); // Fetching rough coordinates...

Ma cosa succede se due interfacce hanno la stessa firma del metodo?

Domanda fantastica. In tal caso, se non si fornisce l'implementazione nella classe, il compilatore scadente si confonderà e semplicemente fallirà! È inoltre necessario fornire un'implementazione del metodo predefinito all'interno della classe. C'è anche un modo ingegnoso superper chiamare l'implementazione che ti piace:

public interface Radio { // public void startRadio(); // public void stopRadio(); default public void next() { System.out.println("Next from Radio"); } } public interface MusicPlayer { // public void start(); // public void pause(); // public void stop(); default public void next() { System.out.println("Next from MusicPlayer"); } } public class Smartphone implements Radio, MusicPlayer { public void next() { // Suppose you want to call MusicPlayer next MusicPlayer.super.next(); } } Smartphone motoG = new Smartphone(); motoG.next(); // Next from MusicPlayer

Metodi statici nelle interfacce

Un'altra novità di Java 8 è la possibilità di aggiungere metodi statici alle interfacce. I metodi statici nelle interfacce sono quasi identici ai metodi statici nelle classi concrete. L'unica grande differenza è che i staticmetodi non vengono ereditati nelle classi che implementano l'interfaccia. Ciò significa che si fa riferimento all'interfaccia quando si chiama il metodo statico e non alla classe che lo implementa.

interface MusicPlayer { public static void commercial(String sponsor) { System.out.println("Now for a message brought to you by " + sponsor); } public void play(); } class Smartphone implements MusicPlayer { public void play() { System.out.println("Playing from smartphone"); } } class Main { public static void main(String[] args) { Smartphone motoG = new Smartphone(); MusicPlayer.commercial("Motorola"); // Called on interface not on implementing class // motoG.commercial("Motorola"); // This would cause a compilation error } }

Ereditare un'interfaccia

È anche possibile in Java che un'interfaccia erediti un'altra interfaccia, usando, hai indovinato, la extendsparola chiave:

public interface Player { public void start(); public void pause(); public void stop(); } public interface MusicPlayer extends Player { default public void next() { System.out.println("Next from MusicPlayer"); } }

Ciò significa che l' MusicPlayerinterfaccia di implementazione della classe deve implementare tutti i metodi MusicPlayere Player:

public class SmartPhone implements MusicPlayer { public void start() { System.out.println("start"); } public void stop() { System.out.println("stop"); } public void pause() { System.out.println("pause"); } }

Quindi ora hai una buona conoscenza delle interfacce Java! Scopri le classi astratte per vedere come Java ti offre un altro modo per definire i contratti.