web-dev-qa-db-fra.com

Nom générique Java Clash, a le même effacement

J'ai la super-classe Foo. Et un bar de classe qui l'étend.

public class Bar extends Foo

Fonction dans Foo:

protected void saveAll(Collection<?> many)

Fonction dans le bar:

public void saveAll(Collection<MyClass> stuff) {
   super.saveAll(stuff);
}

Obtenir une erreur:

 Name clash: The method saveAll(Collection<MyClass>) of type Bar has the same erasure as saveAll(Collection<?>) of type Foo but does not override it.

Qu'est-ce que je fais mal?

25
Jaanus

Vous substituez la méthode saveAll à un type incompatible. Peut-être que vous voulez faire quelque chose comme:

public class Bar extends Foo<MyClass>

Fonction dans Foo<E>

protected void saveAll(Collection<E> many)

et fonction dans le bar:

public void saveAll(Collection<MyClass> stuff) {
   super.saveAll(stuff);
}
17
Mathias Schwarz

En raison de la fonctionnalité de suppression de type de Java, la machine virtuelle Java ne sera pas en mesure de savoir si c'est la méthode qui a le type paramétré MyClass ou la première à appeler.

Si cela est possible ou applicable, le motif le plus couramment utilisé pour éviter cela est de changer la classe Foo pour avoir également un type paramétré:

public class Foo<T> {
    protected void saveAll(Collection<T> many) {}
}

puis faites simplement en sorte que Bar implémente Foo pour votre type spécifique:

public class Bar extends Foo<MyClass> {
    public void saveAll(Collection<MyClass> many) {
        super.saveAll(many);
    }
}
8
Joel Westberg

Au moment de l'exécution, les types de paramètre sont remplacés par Object. Donc saveAll(Collection<?>) et saveAll(Collection<MyClass>) sont transformés en saveAll(Collection). Ceci est un choc de noms . Regardez ici pour plus de détails.

Vous pourriez faire ceci:

public class Foo<T> {
    protected void saveAll(Collection many) {
        // do stuff
    }
}

public class Bar extends Foo<MyClass> {
}
4
gontard

Lorsque les compilateurs compilent en code octet, un processus appelé Erasure se produit. Cela supprime les informations de type des collections. Je crois que cela fera manuellement les moulages, etc. dans le cadre du processus de génération du code octet. Si vous supprimez les parties génériques de votre classe (c'est-à-dire le <..>), vous verrez que vous avez deux méthodes saveAll. L'erreur est que vous avez deux enregistrer toutes les méthodes seront la même signature. Les collections ont un objet type dans le code d'octet.

Essayez de supprimer le <..> qui pourrait le rendre plus clair. Lorsque vous remettez le <...>, considérez le nom des méthodes. Si elles sont différentes, il devrait être compilé.

De plus, je ne pense pas qu'il s'agisse d'un problème d'hibernation, vous devez donc supprimer cette balise. C'est un problème générique Java que vous avez.

Ce que vous pouvez faire ici est de taper la classe

public class Bar extends Foo<MyClass>

puis avoir les types de méthode à T

public void saveAll(Collection<MyClass> stuff) {
   super.saveAll(stuff);
}

et puis la déclaration de Foo serait quelque chose comme

public abstract class Bar extends Foo<T> {
    public void saveAll(Collection<T> stuff) {
}
2
RNJ

Vous venez de surcharger des méthodes avec différentes signatures. 

La bonne idée est d’utiliser la règle PECS (Producer - Extends, Consumer - Super) décrite dans Effective Java Second Edition de Joshua Bloch. 

selon cette règle, il devrait ressembler à ceci.

En classe Foo:

public class Foo<E>{

protected void saveAll(Collection<? super E> many){....}

protected void getAll(Collection<? extends E> many){....}

}
1
danny.lesnik

Bien que les réponses existantes soient correctes, cette erreur se produit facilement lorsque vous déclarez le type réel non pas dans la clause "extends ..." mais dans le nom de classe actuel:

Faux:

public class Bar<MyClass> extends Foo
{
    ...
}

Correct:

public class Bar extends Foo<MyClass>
{
    ...
}
0
MRalwasser