7
votes

Liste générique simple en Java

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. xxx pré>

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 code> et Liste code> (avec la sortie de l'étendue). Je pensais que nous étends m'a aidé à résoudre un problème qu'ils ne le font pas. Voici donc que mon vrai problème réside: P>

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
  }

}


0 commentaires

5 Réponses :


0
votes

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.


0 commentaires

3
votes

Vous dites que la méthode renvoie une liste " 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 " du tout type que vous souhaitez", vous devez donc faire la méthode générique: xxx

ok, je viens de regarder votre MISE À JOUR:

Tout dépend de ce que vous avez l'intention de pouvoir faire avec le résultat de getdogs () . Si vous n'avez pas l'intention de pouvoir ajouter des éléments à la liste, alors getdogs () doit revenir type liste , puis le problème serait résolu.

Si vous avez l'intention de pouvoir y ajouter des choses, et par le type Liste Cela signifie que vous pouvez ajouter tout type de chien à celui-ci, puis logiquement, cette liste ne peut pas être la même liste que greyhounds , car greyhounds a type Liste et donc chien ne doit pas y aller.

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 greyhouds .


2 commentaires

Ce n'est pas très utile à moins qu'il ne renvoie une liste vide (ou une liste de null s).


Cheers, Generics est ce que i était à la recherche.



3
votes

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();
}


0 commentaires

1
votes

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> xxx pré>

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>

  1. Essayez de retourner une nouvelle liste comme vous le suggérez dans votre commentaire. Par exemple, retourne nouvelle arrayliste (this.greyhounds); code> p> li>

  2. 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 code> à laquelle vous ajoutez vos greyhounds spécifiques. I.e., Liste protégée Greyhoundsonly; Code> où vous gérez quels chiens sont autorisés dans le chenil via l'interface externe de l'objet. P> LI> ol>

    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> xxx pré>

    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>

    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);
      }
    
    }
    


6 commentaires

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é") .


@ 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.



0
votes

Il existe déjà une réponse acceptée, cependant, les PLS considèrent la modification de code suivante. XXX PRE>

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
    }
}


2 commentaires

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.