2015-09-24 7 views
11

Sto provando a scrivere una libreria di interfacce di raccolta che implementa la maggior parte dei metodi nell'API di raccolta standard utilizzando la nuova sintassi del metodo predefinito in Java 8. Ecco un piccolo esempio di ciò vado a fare:Errore Java 8: Eredita dell'interfaccia astratta e predefinita

public interface MyCollection<E> extends Collection<E> { 
    @Override default boolean isEmpty() { 
     return !iterator().hasNext(); 
    } 
    //provide more default overrides below... 
} 

public interface MyList<E> extends MyCollection<E>, List<E> { 
    @Override default Iterator<E>iterator(){ 
     return listIterator(); 
    } 
    //provide more list-specific default overrides below... 
} 

Tuttavia, anche questo semplice esempio è incontrato con un errore di compilazione:

error: interface MyList<E> inherits abstract and default 
     for isEmpty() from types MyCollection and List 

Dalla mia comprensione di metodi predefiniti, questo dovrebbe essere permesso in quanto solo uno dei esteso interfacce fornisce un'implementazione predefinita, ma ap parently non è il caso. Cosa sta succedendo qui? C'è un modo per ottenere ciò per fare ciò che voglio?

risposta

8

questo è spiegato nel section 9.4.1.3 (Inheriting Methods with Override-Equivalent Signatures) del linguaggio Java Specification:

It is possible for an interface to inherit several methods with override-equivalent signatures (§8.4.2).

...

Similarly, when an abstract and a default method with matching signatures are inherited, we produce an error. In this case, it would be possible to give priority to one or the other - perhaps we would assume that the default method provides a reasonable implementation for the abstract method, too. But this is risky, since other than the coincidental name and signature, we have no reason to believe that the default method behaves consistently with the abstract method's contract - the default method may not have even existed when the subinterface was originally developed. It is safer in this situation to ask the user to actively assert that the default implementation is appropriate (via an overriding declaration).

Quindi, dal momento sia MyCollection e List definire un metodo isEmpty() e uno è di default e l'altro è astratto, il compilatore richiede l'sottointerfaccia di dichiarare in modo esplicito quale dovrebbe ereditare sovrascrivendo il metodo. Se si desidera che il metodo di default di MyCollection essere ereditata, allora si può invocarlo nella realizzazione prioritario:

public interface MyList<E> extends MyCollection<E>, List<E> { 
    @Override default boolean isEmpty() { 
     return MyCollection.super.isEmpty(); 
    } 

    @Override default Iterator<E> iterator(){ 
     return listIterator(); 
    } 
    ... 
} 

Se si desidera MyList per mantenere il isEmpty() astratta (che non credo che si vuole), è può fare:

public interface MyList<E> extends MyCollection<E>, List<E> { 
    @Override boolean isEmpty(); 

    @Override default Iterator<E> iterator(){ 
     return listIterator(); 
    } 
    ... 
} 
+0

La necessità di duplicare tutte queste firme di metodo è deludente, ma questo sembra esattamente quello che stavo cercando. Accettato, supponendo che non ci sia modo di evitarlo. –

+2

La cosa veramente negativa è che non c'è alcun motivo per 'List' per redeclare' isEmpty() '. Il suo unico scopo sembra essere quello di modificare il commento della documentazione dall'eredità "Restituisce true se questa raccolta non contiene elementi." Al più specifico "Restituisce true se questo elenco non contiene elementi." Senza questo, tutto funzionerebbe come prima ma il compilare l'errore da questa domanda sarebbe andato come 'MyCollection.isEmpty()' sovrascrive 'Collection.isEmpty()' ... – Holger

+1

@Holger Hai ragione in questo caso. Ma per altri metodi come 'toArray', la documentazione differisce maggiormente in termini di contratto del metodo. Penso che questo problema si presenta come un prezzo per l'utilizzo di metodi predefiniti. – manouti

0

modificare il codice sorgente per

public interface MyList<E> extends MyCollection<E>,List<E> { 
    @Override 
    default boolean isEmpty(){ 
      return MyCollection.super.isEmpty(); 
     } 
} 

per ulteriori informazioni seguire il link, default implementation in interface

+0

la chiamata a 'MyCollection.super.isEmpty() 'è superfluo –

+0

si !! aggiornerà il codice. – snAtchnAren