2016-07-05 39 views
8

Mi sono imbattuto in qualcosa che trovo strano in Java e non sono riuscito a trovare molte informazioni su di esso. Si consideri il seguente codice:Metodi generici e astratti

public class TestClass { 

    private static abstract class AbstractClass { 
     abstract List<? extends Object> getList(); 
     abstract Map<Long, List<? extends Object>> getMap(); 
    } 

    private static final class ConcreteClass extends AbstractClass { 
     @Override 
     List<String> getList() { 
      return null; 
     } 

     @Override 
     Map<Long, List<String>> getMap() { 
      return null; 
     } 
    } 
} 

Il compilatore mostra un errore sul metodo getMap():

getMap() in ConcreteClass cannot override getMap() in AbstractClass 
    return type Map<Long, List<String>> is not compatible with Map<Long, List<? extends Object>> 

Ma lo stesso errore non è presente per il metodo getList(), ma mi sarei aspettato uno sia per lavorare o sia per fallire. In entrambi i casi, il metodo di sostituzione è delcaring List<String> al posto di List<? extends Object>. Qualcuno può spiegarlo?

risposta

10

È perché esiste una conversione implicita da List<String> a List<? extends Object>, ma non da Map<Long, List<String>> a Map<Long, List<? extends Object>>.

Tutti i tipi generici sono invarianti a meno che non si utilizzino tipi di caratteri jolly. Poiché non esiste alcun carattere jolly negli argomenti di tipo generico del tipo di mappa "esterno", non è possibile acquisire alcun tipo generico che non corrisponda esattamente.

Se il tipo di mappa fosse Map<Long, ? extends List<? extends Object>>, funzionerebbe come previsto.

E l'altra parte se la risposta è che le sottoclassi possono sovrascrivere o implementare un metodo supertipo con un tipo di ritorno diverso, ma solo se il tipo di ritorno del metodo del sottotipo è implicitamente convertibile nel tipo di ritorno del metodo supertipo. (Anche in Java 1.4 e sotto non funzionerebbe: sarebbe un errore di compilazione se i tipi non corrispondessero esattamente.)

+0

Ottima risposta, grazie! (Accetterò dopo che il limite di tempo è scaduto) – lucasvw

+3

il punto buono, mi piacerebbe aggiungere '? extends Object' può essere sostituito con '?' senza alcun effetto – Andrew

+2

@Andrew: certo, ma lo stesso principio vale per qualsiasi limite inferiore sul carattere jolly, non solo 'Object'. –