JavaRush /Java Blog /Random-IT /Interfacce in Java

Interfacce in Java

Pubblicato nel gruppo Random-IT
Ciao! Oggi parleremo di un concetto importante in Java: le interfacce. Probabilmente la parola ti è familiare. Ad esempio, la maggior parte dei programmi e dei giochi per computer dispongono di interfacce. In senso lato, un'interfaccia è una sorta di “telecomando” che collega due parti che interagiscono tra loro. Un semplice esempio di interfaccia della vita quotidiana è il telecomando della TV. Collega due oggetti, una persona e una TV, e svolge diverse attività: alzare o abbassare il volume, cambiare canale, accendere o spegnere la TV. Un lato (la persona) deve accedere all'interfaccia (premere il pulsante del telecomando) affinché l'altro lato esegua l'azione. Ad esempio, affinché la TV passi al canale successivo. In questo caso, l'utente non ha bisogno di conoscere il dispositivo del televisore e come viene implementato il processo di cambio canale al suo interno. Perché abbiamo bisogno di interfacce in Java - 1Tutto ciò a cui l'utente ha accesso è l'interfaccia . Il compito principale è ottenere il risultato desiderato. Cosa c'entra questo con la programmazione e Java? Diretto :) La creazione di un'interfaccia è molto simile alla creazione di una classe normale, ma al posto della parola classspecifichiamo la parola interface. Diamo un'occhiata all'interfaccia Java più semplice e scopriamo come funziona e a cosa serve:
public interface Swimmable  {

     public void swim();
}
Abbiamo creato un'interfaccia Swimmableche può nuotare . Questo è qualcosa come il nostro telecomando, che ha un “pulsante”: il metodo swim() è “nuota”. Come possiamo utilizzare questo “ telecomando ”? A questo scopo il metodo, ad es. Il pulsante sul nostro telecomando deve essere implementato. Per utilizzare un'interfaccia, i suoi metodi devono essere implementati da alcune classi del nostro programma. Creiamo una classe i cui oggetti corrispondano alla descrizione "sa nuotare". Ad esempio, la classe duck è adatta Duck:
public class Duck implements Swimmable {

    public void swim() {
        System.out.println("Duck, swim!");
    }

    public static void main(String[] args) {

        Duck duck = new Duck();
        duck.swim();
    }
}
Cosa vediamo qui? Una classe Duckè associata a un'interfaccia Swimmableutilizzando la parola chiave implements. Se ricordi, abbiamo utilizzato un meccanismo simile per collegare due classi in ereditarietà, solo che c'era la parola “ extends ”. “ public class Duck implements Swimmable” può essere tradotto letteralmente per chiarezza: “una classe pubblica Duckimplementa l’interfaccia Swimmable”. Ciò significa che una classe associata ad un'interfaccia deve implementare tutti i suoi metodi. Nota: nella nostra classe, Duckproprio come nell'interfaccia , Swimmablec'è un metodo swim()e al suo interno c'è una sorta di logica. Questo è un requisito obbligatorio. Se scrivessimo semplicemente “ public class Duck implements Swimmable” e non creassimo un metodo swim()nella classe Duck, il compilatore ci darebbe un errore: Duck non è astratto e non sovrascrive il metodo astratto swim() in Swimmable Perché succede questo? Se spieghiamo l'errore usando l'esempio di una TV, si scopre che stiamo dando a una persona un telecomando con un pulsante "cambia canale" da una TV che non sa come cambiare canale. A questo punto premi il pulsante quanto vuoi, non funzionerà nulla. Il telecomando in sé non cambia canale: fornisce solo un segnale al televisore, all'interno del quale viene implementato un complesso processo di cambio canale. Così è anche per la nostra papera: deve saper nuotare affinché sia ​​possibile accedervi tramite l'interfaccia Swimmable. Se non sa come farlo, l'interfaccia Swimmablenon collegherà le due parti: la persona e il programma. Una persona non sarà in grado di utilizzare un metodo swim()per rendere Duckmobile un oggetto all'interno di un programma. Ora hai visto più chiaramente a cosa servono le interfacce. Un'interfaccia descrive il comportamento che devono avere le classi che implementano quell'interfaccia. “Comportamento” è un insieme di metodi. Se vogliamo creare più messenger, il modo più semplice per farlo è creare un'interfaccia Messenger. Cosa dovrebbe essere in grado di fare qualsiasi messenger? In una forma semplificata, ricevi e invia messaggi.
public interface Messenger{

     public void sendMessage();

     public void getMessage();
}
E ora possiamo semplicemente creare le nostre classi di messaggistica implementando questa interfaccia. Sarà il compilatore stesso a “costringerci” ad implementarli all’interno delle classi. Telegramma:
public class Telegram implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a message to Telegram!");
    }

     public void getMessage() {
         System.out.println("Reading the message in Telegram!");
     }
}
WhatsApp:
public class WhatsApp implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a WhatsApp message!");
    }

     public void getMessage() {
         System.out.println("Reading a WhatsApp message!");
     }
}
Viber:
public class Viber implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a message to Viber!");
    }

     public void getMessage() {
         System.out.println("Reading a message in Viber!");
     }
}
Quali vantaggi offre questo? Il più importante di questi è l'accoppiamento lento. Immagina di progettare un programma in cui raccoglieremo i dati dei clienti. La classe Clientdeve avere un campo che indica quale messenger utilizza il client. Senza interfacce sembrerebbe strano:
public class Client {

    private WhatsApp whatsApp;
    private Telegram telegram;
    private Viber viber;
}
Abbiamo creato tre campi, ma un cliente può facilmente avere un solo messenger. Semplicemente non sappiamo quale. E per non rimanere senza comunicazione con il cliente, devi "spingere" tutte le opzioni possibili nella classe. Si scopre che uno o due di essi saranno sempre presenti nulle non saranno affatto necessari affinché il programma funzioni. Invece, è meglio usare la nostra interfaccia:
public class Client {

    private Messenger messenger;
}
Questo è un esempio di “accoppiamento allentato”! Invece di specificare una classe messenger specifica nella classe Client, menzioniamo semplicemente che il client ha un messenger. Quale sarà determinato durante il corso del programma. Ma perché abbiamo bisogno di interfacce per questo? Perché sono stati aggiunti alla lingua? La domanda è buona e corretta! Lo stesso risultato si può ottenere utilizzando l'ereditarietà ordinaria, giusto? La classe Messengerè la classe genitore e , Vibere Telegramsono WhatsAppgli eredi. In effetti, è possibile farlo. Ma c'è un problema. Come già sai, in Java non esiste l'ereditarietà multipla. Ma esistono molteplici implementazioni di interfacce. Una classe può implementare quante interfacce desidera. Immagina di avere una classe Smartphonecon un campo Application: un'applicazione installata su uno smartphone.
public class Smartphone {

    private Application application;
}
L'applicazione e il messenger sono, ovviamente, simili, ma sono comunque cose diverse. Messenger può essere sia mobile che desktop, mentre Application è un'applicazione mobile. Quindi, se utilizzassimo l'ereditarietà, non saremmo in grado di aggiungere un oggetto Telegramalla classe Smartphone. Dopo tutto, una classe Telegramnon può ereditare da Applicatione da Messenger! E siamo già riusciti a ereditarlo da Messengere ad aggiungerlo alla classe in questa forma Client. Ma una classe Telegrampuò facilmente implementare entrambe le interfacce! Pertanto, in una classe Clientpossiamo implementare un oggetto Telegramcome Messenger, e in una classe Smartphonecome Application. Ecco come è fatto:
public class Telegram implements Application, Messenger {

    //...methods
}

public class Client {

    private Messenger messenger;

    public Client() {
        this.messenger = new Telegram();
    }
}


public class Smartphone {

    private Application application;

    public Smartphone() {
        this.application = new Telegram();
    }
}
Ora possiamo usare la classe Telegramcome vogliamo. Da qualche parte agirà nel ruolo di Application, da qualche parte nel ruolo di Messenger. Probabilmente hai già notato che i metodi nelle interfacce sono sempre “vuoti”, ovvero non hanno alcuna implementazione. La ragione di ciò è semplice: un'interfaccia descrive il comportamento, non lo implementa. “Tutti gli oggetti delle classi che implementano l’interfaccia Swimmabledevono poter fluttuare”: questo è tutto ciò che ci dice l’interfaccia. Come nuoterà esattamente un pesce, un'anatra o un cavallo è una domanda per le classi Fish, Ducke Horse, e non per l'interfaccia. Proprio come cambiare canale è compito di una TV. Il telecomando ti dà semplicemente un pulsante per farlo. Tuttavia, Java8 ha un'aggiunta interessante: i metodi predefiniti. Ad esempio, la tua interfaccia ha 10 metodi. 9 di essi sono implementati in modo diverso in classi diverse, ma uno è implementato allo stesso modo in tutte. In precedenza, prima del rilascio di Java8, i metodi all'interno delle interfacce non avevano alcuna implementazione: il compilatore generava immediatamente un errore. Ora puoi farlo in questo modo:
public interface Swimmable {

   public default void swim() {
       System.out.println("Swim!");
   }

   public void eat();

   public void run();
}
Utilizzando la parola chiave default, abbiamo creato un metodo nell'interfaccia con un'implementazione predefinita. Dovremo implementare gli altri due metodi eat()e run()noi stessi in tutte le classi che implementeranno Swimmable. Non è necessario farlo con il metodo swim(): l'implementazione sarà la stessa in tutte le classi. A proposito, ti sei imbattuto in interfacce più di una volta nelle attività precedenti, anche se non te ne sei accorto tu stesso :) Ecco un esempio ovvio: Perché abbiamo bisogno di interfacce in Java - 2hai lavorato con le interfacce Liste Set! Più precisamente, con le loro implementazioni - , ArrayListe altri. Lo stesso diagramma mostra un esempio in cui una classe implementa più interfacce contemporaneamente. Ad esempio, implementa le interfacce e (coda fronte-retro). Conosci anche l'interfaccia , o meglio, le sue implementazioni - . A proposito, in questo diagramma puoi vedere una caratteristica: le interfacce possono essere ereditate l'una dall'altra. L'interfaccia è ereditata da ed è ereditata dalla coda . Ciò è necessario se vuoi mostrare la connessione tra le interfacce, ma un'interfaccia è una versione estesa di un'altra. Consideriamo un esempio con un'interfaccia : una coda. Non abbiamo ancora esaminato le collezioni , ma sono piuttosto semplici e disposte come una fila regolare in un negozio. Puoi aggiungere elementi solo alla fine della coda e rimuoverli solo dall'inizio. Ad un certo punto, gli sviluppatori avevano bisogno di una versione ampliata della coda in modo che gli elementi potessero essere aggiunti e ricevuti da entrambe le parti. È così che è stata creata un'interfaccia : una coda bidirezionale. Contiene tutti i metodi di una coda normale, perché è il “genitore” di una coda bidirezionale, ma sono stati aggiunti nuovi metodi. LinkedListHashSetLinkedListListDequeMapHashMapSortedMapMapDequeQueueQueueQueueDeque
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION