2010-10-16 27 views
6

Comme un exemple concret de la question générale du sujet, je voudrais mettre en œuvre la méthode containsAll dans l'interface Set avecmise en œuvre Interface avec l'argument de la méthode SuperClasses

public boolean containsAll(Iterable<?> c) { /* ... */ } 

Je figure cela devrait être permis, depuis Collection est Iterable ce qui signifie qu'un tel containsAll couvrirait l'exigence d'interface. De même, plus généralement, être capable d'implémenter des interfaces avec des superclasses d'arguments semble fonctionner. Cependant, Eclipse ne dit pas du tout (n'a pas essayé juste javac straight-up) - quelqu'un peut-il expliquer la raison de cela? Je suis sûr qu'il y a quelque chose dans la spécification qui fait que c'est comme ça, mais je voudrais comprendre la motivation pour l'exigence aussi bien. Ou est-ce que je manque quelque chose comme Iterable<?> n'étant pas une superclasse de Collection<?>? Comme une question secondaire - étant donné que je déclare deux méthodes serait la méthode avec la signature Iterable toujours préférée sur les appels avec un argument Collection?

Eclipse Erreur:

Si je supprime la méthode avec la signature Collection, tout en laissant le Iterable un (voir après erreur), je reçois le texte suivant:

The type BitPowerSet must implement the inherited abstract method Set<Long>.containsAll(Collection<?>)

L'être de mise en œuvre exacte :

@Override public boolean containsAll(Collection<?> c) { 
    for (Object o : c) if (!contains(o)) return false; 
    return true; 
} 
public boolean containsAll(Iterable<?> c) { 
    for (Object o : c) if (!contains(o)) return false; 
    return true; 
} 
+0

Pourriez-vous poster une erreur qu'Eclipse vous offre? Travaille pour moi à IDEA. –

+0

@Nikita: édité dans. Soooo ... ça pourrait être juste une chose Eclipse? – Carl

+0

Celui-ci est un cauchemar terminologique. Je fuis de tels défis. – skaffman

Répondre

2

Je pense que la raison pour laquelle java a cette restriction est, disons que vous avez:

class A { 
    void foo(String s) { ... } 
} 

class B extends A { 
    // Note generalized type 
    @Override void foo(Object s) { ... } 
} 

Maintenant, si vous avez class C extends B et il veut passer outre foo, on ne sait pas quel argument il devrait prendre.

Say par exemple C prolongée A directement au premier, remplaçant void foo(String s), puis il a été changé pour étendre B. Dans ce cas, la dérogation existante C de foo deviendrait invalide parce que B foo devrait être capable de gérer tous les Object s, non juste String s.

+0

ah, cela semble être une explication raisonnable - l'élargissement de l'interface exigerait que les sous-classes maintiennent l'interface élargie. Pourtant, cela semble devoir être autorisé - typiquement, les sous-classes ne sont pas autorisées à restreindre les interfaces. – Carl

+0

Il rend également probablement la conception de la table virtuelle plus claire pour affirmer que toutes les méthodes qui s'y trouvent ont la signature exacte. Ou peut-être pensaient-ils simplement qu'ils pourraient le faire fonctionner s'ils le détaillaient suffisamment, mais ne voyaient pas un besoin impérieux et l'ignoraient. – oksayt

+0

Il me manque quelque chose - cet exemple est-il censé fonctionner? Sur l'annotation @Override, j'obtiens "La méthode ne remplace pas la méthode de sa super-classe". – Amalgovinus

5

Depuis l'interface que vous implémentez déclare le (résumé) méthode containsAll(Collection<?>), vous devez l'implémenter avec cette signature exacte. Java ne vous permet pas d'implémenter/remplacer une méthode avec un type de paramètre plus large que l'original. C'est pourquoi vous obtenez l'erreur que vous affichez lorsque vous commentez votre méthode avec la signature Collection.

Vous ne montrez pas l'autre erreur que vous prétendez obtenir lorsque la méthode n'est pas commentée, mais je suppose que cela pourrait avoir à faire quelque chose avec une surcharge de méthode ambiguë.

+0

Il n'y a pas d'erreur lorsque la méthode n'est pas commentée. Seulement quand celui avec la signature 'Collection' est. – Carl

+0

En outre, un aperçu de pourquoi c'est le cas? Est-ce dans le sens de la réponse de @ oksayt? – Carl

+0

@Carl, vous voulez dire pourquoi Java est conçu ainsi? Pourrait être. –

0

Les types d'argument font partie de la signature de la méthode, de sorte que jvm a besoin d'une méthode avec exactement la même signature pour trouver les remplacements. Une containsAll (Iterable) aura une signature différente de celle de containsAll (Collection). Si je me souviens bien, le compilateur doit utiliser certaines solutions pour faire fonctionner les génériques malgré cette limitation.Pour votre deuxième question, le compilateur préférerait l'argument Collection puisqu'il s'agit d'un sous-type d'Iterable, ce qui rend la méthode Collection plus spécifique que la méthode Iterable.