Pourquoi les génériques Java sont-ils si difficiles? Je pensais enfin compris, mais Eclipse me donne une erreur à la ligne de SomotherMethod ci-dessous en utilisant l'une des méthodes getouterlist ci-dessous. update strong>: OK - je comprends donc l'erreur maintenant. C'était un manque de compréhension de ma part de la liste > Code> ou list EXTENDUE TOOOBJECT> CODE> signifie vraiment. Dans le premier cas, je pensais que cela signifiait une liste qui pourrait contenir quoi que ce soit. Dans ce dernier cas, j'ai supposé que c'était une liste d'objets qui étendent quelqueObject. La représentation appropriée de ma compréhension serait simplement une liste list Liste public interface DogKennel {
public List<Dog> getDogs();
}
public class GreyHoundKennel implements DogKennel {
protected List<GreyHound> greyHounds;
public List<GreyHound> getGreyHounds() {
return this.greyHounds;
}
public List<Dog> getDogs() {
// Is there no way to handle this with generics
// w/out creating a new List?
return getGreyHounds(); //compiler error
}
}
5 Réponses :
Un type générique de? signifie "un type spécifique, mais je ne sais pas quoi". quoi que ce soit en utilisant un? est essentiellement en lecture seule parce que vous ne pouvez pas écrire avec la sortie du type actuel. P>
Vous dites que la méthode renvoie une liste " ok, je viens de regarder votre MISE À JOUR: P> Tout dépend de ce que vous avez l'intention de pouvoir faire avec le résultat de Si vous avez l'intention de pouvoir y ajouter des choses, et par le type ce qui signifie que vous devez créer une nouvelle liste. En gardant à l'esprit bien sûr que toute modification de la nouvelle liste ne serait pas reflétée dans la liste d'origine code> d'un type inconnu" (que vous ne pouvez pas ajouter à, car vous ne pouvez pas garantir que la chose que vous ajoutez est un sous-type de ce type). Vous voulez réellement dire, une liste " code> du tout type que vous souhaitez", vous devez donc faire la méthode générique: getdogs () code>. Si vous n'avez pas l'intention de pouvoir ajouter des éléments à la liste, alors getdogs () code> doit revenir type liste étend votre chien> code>, puis le problème serait résolu. p> Liste greyhounds code>, car greyhounds code> a type Liste chien code> ne doit pas y aller. p> greyhouds code>. P> p>
Ce n'est pas très utile à moins qu'il ne renvoie une liste vide (ou une liste de null code> s).
Cheers, Generics est ce que i b> était à la recherche.
Cette déclaration:
protected List<GreyHound> greyHounds;
// We only want a List of GreyHounds here:
public List<GreyHound> getGreyHounds() {
return this.greyHounds;
}
// The list returned can be a List of any type of Dog:
public List<? extends Dog> getDogs() {
return getGreyHounds();
}
Vous trébuchez sur le fait que les génériques Java ne sont pas polymorphes sur le paramètre de type.
Parler à travers votre fragment de code, tirons l'exemple séparé: p> Votre commentaire original est donc correct. Les deux listes sont définitivement différentes, sans héritage entre eux. Donc, je suggérerais d'enquêter sur ces deux options: p> Essayez de retourner une nouvelle liste comme vous le suggérez dans votre commentaire. Par exemple, Avez-vous vraiment besoin de garder une liste d'une race de chien spécifique? Peut-être devriez-vous définir le membre de données pour être une liste sauf si vous avez une bonne raison de conserver une liste spécifique à un type, je penserais sérieusement à l'option 2. p> EDIT: Frotter mes options suggérées ci-dessus: P> Option 1: retourne une nouvelle liste forte>. Avantages: simple, simple, vous obtenez une liste dactylographiée et elle élimine un problème de sécurité de thread-sécurité (n'expose pas une référence interne au monde). Inconvénients: apparemment un coût de performance. P> option 2: Utilisez une différence de données différente forte>. Avantages: joue mieux avec le polymorphisme, retourne la liste générique qui était l'objectif initial. Inconvénients: c'est une architecture légèrement différente qui peut ne pas s'adapter à la tâche d'origine. P>
retourne nouvelle arrayliste Liste protégée public abstract class DogKennel {
protected List<Dog> dogs = new ArrayList<Dog>();
}
public class GreyHoundKennel extends DogKennel {
// Force an interface that only allows what I want to allow
public void addDog(GreyHound greyHound) { dogs.add(greyHound); }
public List<Dog> getDogs() {
// Greatly reduces risk of side-effecting and thread safety issues
// Plus, you get the generic list that you were hoping for
return Collections.unmodifiableList(this.dogs);
}
}
Option n ° 1: Ceci est une performance touchée. Mieux vaut ne pas utiliser de génériques. Option n ° 2: "Est-ce que j'ai vraiment besoin de garder une liste de race de chien spécifique?" Non, mais je pensais que c'est ce que les listes dactènes vous ont acheté? Si je ne peux pas faire cela, alors quel est le point de générique. Ma conclusion: les génériques sont une perte de temps.
@ AndersonBD1, vous pensez honnêtement que l'option 1 est une performance frappée? Combien de chiens suivez-vous à la fois? À moins que ce soit plus d'un millier, vous auriez une période très difficile de mesurer le coût, en particulier lorsque vous le comparez à la commodité de codage de la liste bien dactylographiée étant renvoyée. Si vous souhaitez vraiment une liste dactylographiée, cela vous le donnera (et c'est l'option que j'utilise généralement pour beaucoup de données). Si vous pensez que les génériques sont une perte de temps, vous vous trompez mal.
@BOBRCROSS - Option n ° 1 - Sûr pour 90% des listes, ce n'est pas une performance touchée, mais nous parlons d'une langue à usage général ici. En tant que développeur d'applications, je dois travailler dans la langue comme celle-ci? Oui, je crois que les génériques sont une perte de temps (sauf si bien sûr que vous n'écrivez en réalité les classes de type modèle), mais cela ouvre tout le débat statique-dynamique :-) comme pour moi, je reviens à l'utilisation de collections non typées et @suppresswarnings ("non coché") code>.
@ AndersonBD1, eh bien, je n'ai pas tout le contexte, vous devez donc prendre la meilleure décision qui correspond à votre travail. Je pense que la raison pour laquelle nous nous déclenchons tous les deux à ce stade est que nous parlons dans l'abstrait. Après ma performance Eval (!), Je vais essayer d'ajouter un code plus spécifique à la réponse.
@BOBRCROSS - L'autre chose qui aspire à propos de l'option n ° 1 (création d'une nouvelle liste), est que cela va briser des applications utilisant un proxy pour cette liste (p. Ex. Applications ORM). L'ORM doit savoir quand les choses sont ajoutées et supprimées d'une liste, vous ne pouvez donc pas créer un nouveau sur un caprice.
@ Andersonbd1, comme je l'ai dit, je n'ai pas tout le contexte. Mon travail est beaucoup plus déclaratif. Lorsque je veux un comportement de manière approfondie, j'utilise généralement une liste de copie ou similaire. Cela fonctionne pour moi mais (basé sur vos commentaires) ne pourrez probablement pas pour vous.
Il existe déjà une réponse acceptée, cependant, les PLS considèrent la modification de code suivante. Les génériques Java sont effectivement cassés, mais pas cassés.
BTW Scala résout cela de manière très élégante en fournissant une manipulation de variance. P> Mise à jour ------------ P> Veuillez considérer un extrait de code mis à jour. P > public interface DogKennel<T extends Dog> {
public List<T> getDogs();
}
public class GreyHoundKennel implements DogKennel<GreyHound> {
private List<GreyHound> greyHounds;
public List<GreyHound> getDogs() {
return greyHounds; // no compilation error
}
public static void main(String[] args) {
GreyHoundKennel inst = new GreyHoundKennel();
inst.getDogs().add(new GreyHound()); // no compilation error
}
}
Mais vous ne pouvez pas ajouter à la liste renvoyée à partir de getdogs - ce qui a commencé cette discussion.
Mes excuses - Je me suis concentré davantage sur la deuxième partie de votre message. Pls considèrent une approche alternative dans la section Mise à jour. Les pls notent également que, en règle générale, il vaut mieux ne pas muter directement les propriétés de collection. Au lieu de cela, il est recommandé de fournir des méthodes de mutateur distinctes telles que l'adddog, l'enlèvement et pour le getter pour renvoyer une collection non modifiable, comme proposé dans la réponse acceptée.