Due interfacce con la stessa firma del metodo implementata in class Java

Ho due interfacce Java e una class di implementazione.

(Ho usato Eclipse per eseguire direttamente il programma, e non ho provato a controllare qualsiasi avvertimento del compilatore e così via compilando esplicitamente dalla riga di comando.)

Perché corrono senza problemi? Perché Java lo consente, anche quando soddisfa il “contratto” di entrambe le interfacce, ma crea ambiguità nell’implementazione della class?

Aggiornato l’esempio

public interface CassettePlayer { void play(); } public interface DVDPlayer { void play(); } public class CarPlayer implements CassettePlayer,DVDPlayer{ @Override public void play() { System.out.println("This plays DVD, screw you Cassette !"); } public static void main(String args[]) { CarPlayer cp = new CarPlayer(); cp.play(); CassettePlayer firstInterface = new CarPlayer(); firstInterface.play(); DVDPlayer secondInterface = new CarPlayer(); secondInterface.play(); } } 

Questo scenario è espressamente consentito nella specifica del linguaggio Java, sezione 8.1.5 :

È consentito per una singola dichiarazione di metodo in una class implementare metodi di più di una superinterfaccia. Ad esempio, nel codice:

 interface Fish { int getNumberOfScales(); } interface Piano { int getNumberOfScales(); } class Tuna implements Fish, Piano { // You can tune a piano, but can you tuna fish? int getNumberOfScales() { return 91; } } 

il metodo getNumberOfScales nella class Tuna ha un nome, una firma e un tipo di ritorno che corrisponde al metodo dichiarato nell’interfaccia Fish e corrisponde anche al metodo dichiarato nell’interfaccia Piano ; si considera che implementa entrambi.

Il testo quindi continua a notare che se le firme del metodo avessero tipi di ritorno diversi, come double e int , non ci sarebbe stato modo di implementare entrambe le interfacce nella stessa class e sarebbe stato generato un errore in fase di compilazione.

Per questo problema è necessario capire a cosa servono le interfacce.

Un’interfaccia è una sorta di “contratto” in modo che si sappia quali metodi sono obbligatoriamente implementati in una Classe con quell’interfaccia.

Quindi se hai bisogno di una class che implementa “DVDPlayer” (perché hai bisogno del metodo “play ()”), troverai CarPlayer. Lo stesso vale per la necessità di una class che implementa CassettePlayer. Questa è la spiegazione tecnica.

Ma ovviamente nella codifica semantica dovresti assicurarti che il metodo “play ()” di CarPlayer soddisfi la semantica sia di DVDPlayer che di CassettePlayer. Penso che in un’applicazione pratica sarà una ctriggers pratica.

Naturalmente nel tuo esempio è una ctriggers idea avere due interfacce che dichiarano lo stesso metodo. Più in pratica, dovresti aver creato un’interfaccia “Player” con il metodo “play ()” e avere altre due interfacce più specifiche, DVDPlayer e CassettePlayer (con metodi specifici per DVD e cassette) che ereditano da Player. D’altra parte, se non hai bisogno di metodi specifici per DVD o cassette, allora non hai bisogno di due interfacce diverse che implementano solo uno stesso metodo – basta usare un’interfaccia Player, sarà sufficiente.

Non c’è conflitto perché entrambi specificano lo stesso contratto, le classi di implementazione forniscono solo l’unico metodo che viene chiamato quando si fa riferimento tramite una delle due interfacce.

Perchè no? La class soddisfa i contratti definiti da entrambe le interfacce.

La class implementa entrambe le interfacce, quindi nessun problema. Ovviamente, questo genere di cose dovrebbe essere evitato in scenari più complessi in cui potrebbe verificarsi un comportamento indesiderato.

La seguente pagina contiene un esempio di una class che implementa due interfacce che hanno il

1) stessa variabile nome 2) stesso metodo in ogni interfaccia.

http://www.j2eeonline.com/java-tm-fundamentals-II/module2/interface-ambiguous-fields.jsp

In questa situazione, non vi è alcun problema perché entrambe le interfacce hanno la stessa firma del metodo. Ma che dire di questo?

 interface Animal { public void eat() throws IOException; } interface Plants { public void eat() throws NullPointerException; } 

Quale è scelto dal compilatore? Perché riceve l’errore sotto il codice?

 public class Test implements Animal, Plants { public void eat() throws IOException { } } 

Il compilatore dice: Eccezione IOException non è compatibile con la clausola throws in Plants.eat ()