12
votes

Variable d'instance générique en classe non générique

J'essaie d'écrire une classe qui a une variable de membre générique mais n'est pas, elle-même, générique. Plus précisément, je tiens à dire que j'ai une liste de valeurs de "un type qui implémente comparable à elle-même", afin que je puisse appeler de sorte que cette liste ... J'espère que cela a du sens.

Le résultat final de ce que J'essaie de faire est de créer une classe de telle sorte que je puisse créer une instance de ladite classe avec un tableau de (tout type donné) et de générer une représentation de chaîne pour cette liste. Dans le code réel, je passe aussi dans la classe des types que je passe: xxx

à l'origine je ne voulais même pas passer dans la classe, je viens de voulait transmettre les valeurs et faire examiner le tableau résultant pour choisir la classe des valeurs ... mais cela me donnait des problèmes aussi.

Ce qui suit est le code que j'ai, mais je Impossible de trouver le bon Mojo à mettre pour le type de variable. xxx

erreur sur la ligne de déclaration de variable: xxx p> Toute aide serait très appréciée.

edit: code mis à jour pour utiliser la liste au lieu d'une matrice, car je ne suis pas sûr de pouvoir être fait avec des tableaux.

@mark: de tout ce que j'ai lu, je veux vraiment dire "T est un type qui est comparable à lui-même", pas seulement " est un type comparable ". Cela étant dit, le code suivant ne fonctionne pas non plus: xxx

erreur sur Ajouter une ligne: xxx

erreur sur ligne de tri: xxx

conclusion:

Qu'est-ce qui va, il apparaît, est que Java ne peut pas tout à fait gérer ce que je veux faire. Le problème est que ce que j'essaie de dire est:

Je veux une liste d'articles qui sont comparable contre eux-mêmes, et je créer la liste entière à la fois de la données passées à la création.

Cependant, Java voit que j'ai cette liste et je ne peux pas découvrir que toutes les informations de ma situation sont disponibles au moment de la compilation, car je pourrais essayer d'ajouter des choses à la liste plus tard et, en raison de Tapez Effacement, il ne peut garantir que la sécurité. Il n'est pas vraiment possible de communiquer à Java les conditions impliquées dans ma situation sans appliquer le type générique à la classe.


3 commentaires

Pourquoi n'est-il pas suffisant d'avoir une liste de choses qui implémentent comparable?


Non pas que cela résout le problème, mais quelque chose d'être comparable ne signifie pas que c'est comparable contre lui-même. Juste la mise en œuvre comparable ne disait pas "est comparable à elle-même".


Vous pouvez le faire avec des méthodes statiques. Voir ma deuxième réponse.


7 Réponses :


7
votes

Je pense que la réponse simple est que vous ne pouvez pas faire cela. Si le type d'un des attributs de classes dépend d'un paramètre de type, ce paramètre doit être déclaré au niveau de la classe. Et je ne pense pas que cela "a du sens" toute autre façon.

si t dans votre exemple n'est pas un paramètre de type de la classe, qu'est-ce que c'est? Il ne peut pas être le paramètre de type de la méthode, car ce type est déterminé par la manière dont la méthode est appelée. (Si la méthode est appelée dans différents contextes statiques avec des types inféré différents pour t , quel est le type noional de t dans le contexte de la déclaration d'attribut?)

afin de ramener ce retour à ce que vous essayez de faire ici, une instance de myClass déposera des éléments d'un type et que vous souhaitez pouvoir insérer et éliminer des éléments de manière statique. Mode Typeafe. Mais en même temps, vous ne voulez pas pouvoir dire ce que ce type est. Ainsi, comment le compilateur est-il supposé statiquement distinguer entre une instance MyClass qui détient (disons) integer objets et une contenant string < / Code> Objets?

Je ne pense même pas que vous puissiez implémenter cela avec des typiques dynamiques explicites. (Je pense que cette effacement signifie que la mise en œuvre de la méthode getsortedlist () ne peut pas savoir quel type réel est lié à son type de retour.)

non. La vraie solution consiste à faire myClass une classe générique qui déclare le paramètre type t ; E.g. xxx

et retirez la déclaration du paramètre de type de niveau de niveau t à partir des deux méthodes.


7 commentaires

Je suis d'accord que T n'a pas de contexte dans cette pièce de code, mais c'est le problème. Tout ce que je veux faire, c'est avoir "une liste d'un type qui peut être comparé contre lui-même, de sorte que je puisse trier ça". C'est-à-dire, apparemment plus difficile que cela ne sonne dans une classe qui n'est pas générique.


Ce n'est que dur (en fait impossible) parce que vous essayez d'éviter de rendre la classe elle-même générique.


C'est juste ça, cependant. Conceptuellement, la classe n'est pas générique. Bien sûr, je peux rendre la classe générique pour résoudre le problème, mais j'espérais qu'il y avait un moyen de l'éviter parce que c'est une odeur de code. Peut-être un requis par la langue, mais un code sent néanmoins.


Je ne veux pas ajouter de manière dynamique des éléments à la liste. Je souhaite créer une liste des éléments (comparables à eux-mêmes) passés au moment de la création et stockez cette liste dans une variable de membre. La classe elle-même n'a rien à voir sur le type ... La variable membre elle-même devrait tenir cette information.


Marquant celui-ci comme accepté. Je pense que c'est légèrement de base avec ce que je suis "essaie" de faire, certaines choses indiquées font clairement que Java ne peut tout simplement pas gérer ce type de chose, principalement en raison de l'effacement de type ... même si c'est parce que c'est parce qu'il se casse Dans des conditions, je ne veux pas gérer de toute façon.


Je pense que le facteur clé ici est que la variable de membre stockant la liste des éléments ne doit pas nécessairement être définie comme une liste des éléments (comparables à eux-mêmes) car il est établi par la définition du constructeur que ce qui est Être transmis est déjà une telle liste.


Je pense que l'idée est agréable d'avoir comme Enums ne fonctionne pas avec des génériques



1
votes

considère comme ceci (ce que je suis sur le point de dire n'est pas la réalité. Mais il illustre pourquoi vous devez faire ce que vous devez faire):

class IntegerFoo
{
    private Integer value;

    Integer getValue() { return value; }
    void setValue(Integer val) {value = val; }
}

class StringFoo
{
    private String value;

    String getValue() { return value; }
    void setValue(String val) {value = val; }
}

// some code that uses the above class

IntegerFoo iFoo = new IntegerFoo();
StringFoo< sFoo = new StringFoo();
iFoo.setValue(5);
sFoo.setValue("Hello");


2 commentaires

J'ai ajouté un peu plus de détails sur ce que j'essaie de faire. Le court est que j'ai une variable de membre qui est une liste que je veux trier, mais peut être une liste de tout type (triable). La classe elle-même n'est pas une classe "de ce type", en soi .. juste cette variable est.


Quelque chose comme New MyClass (Integer.class, .........); n'est pas une pratique rare.



1
votes

Je crois que ce qui suit sera atteint ce que vous voulez (dactylographie plus forte de comparable). Cela empêchera les personnes qui ajoutent des objets comparables qui ne sont pas de votre interface à la liste et permettront de mettre plusieurs implémentations.

 public class test {
  final List<ComparableType> values = new ArrayList<ComparableType>();

  public test (ComparableType... values) {
      for(ComparableType item : values) {
          this.values.add(item);
      }
  }

  public List<ComparableType> getSortedLst() {
      Collections.sort(this.values);
      return Collections.unmodifiableList(this.values);
  }
}


2 commentaires

Vous vous retrouvez toujours avec une classe générique là-bas, plus vous supprimez la possibilité de créer une instance avec des classes système telles que la chaîne.


Édité pour indiquer qu'il fonctionne facilement sans la classe principale en cours de générique. Je pense que l'objectif est que seuls les comparables approuvés puissent être utilisés (c'est-à-dire que la chaîne n'est pas utilisable par la conception).



3
votes

Il y a beaucoup d'avertissements non contrôlés dans cela, mais en principe, il n'est pas nécessaire de garder la liste comme quelque chose que quelque chose contenant des choses que vous connaissez est comparable . Vous exécutez les règles dont vous avez besoin dans le constructeur et tout le reste devrait être bien. Que diriez-vous de quelque chose comme ceci: xxx

Un test rapide en utilisant ce qui suit montre que pour les classes qui implémentent comparables (comme entier et une chaîne) myClass se comporte comme prévu, mais Lancer une erreur de compilation pour les classes qui ne mettent pas en œuvre comparable : xxx


4 commentaires

Cela vient assez près de ce que je cherche. Cela étant dit, il y a un autre morceau de puzzle (un peu connexe mais le rend plus complexe que je ne veux gérer dans la quête) qui me morde quand je vais de cette façon. J'apprécie la réponse, cependant.


@RHSeeger, puisque cela répond fondamentalement à votre question, j'apprécierais un peu plus d'informations sur la raison pour laquelle il ne suffit pas ...


Le principal problème était que je voulais vraiment que les variables des membres qui disaient "un type qui implémente comparable à elle-même", plutôt que simplement "un type qui implémente comparable", autant pour le code de documentation automatique que pour d'autres pièces de code qui veulent une telle valeur comme entrée. Cela étant dit, je déteste aussi de voir des avertissements non contrôlés, de la mine personnelle de la mienne qui est plus avec le mauvais design de Java que toute autre chose.


@RHSeeger: le code auto-documentant est agréable, mais vos fonctions d'accès rendent clairement le cas pour "un type qui implémente comparable à lui-même", la méthode de stockage interne de la classe "est quelque peu pertinente.



-1
votes
public class MyClass<T extends Comparable<? super T>> {
    // This doesn't work as T isn't defined
    final List<T> values;

    public MyClass (T... values) {
        this.values = new ArrayList<T>(Arrays.asList(values));
    }

    public List<T> getSortedLst() {
        Collections.sort(this.values);
        return this.values;
    }
}

0 commentaires

1
votes

Je le ferais de cette façon (je l'ai fait comme une liste ou en tant que tableau), sauf si vous avez vraiment besoin de la variable / des méthodes d'instance:

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;


public class MyClass
{
    public static <T extends Comparable<T>> List<T> asSortedList(final T ... vals)
    {
        final List<T> temp;

        temp = new ArrayList<T>(vals.length);
        temp.addAll(Arrays.asList(vals));
        Collections.sort(temp);

        return (Collections.unmodifiableList(temp));
    }

    public static <T extends Comparable<T>> T[] asSortedArray(final Class<?> clazz,
                                                              final T ...    vals)
    {
        final T[] temp;

        temp = (T[])Array.newInstance(clazz,
                                 vals.length);
        System.arraycopy(vals,
                         0,
                         temp,
                         0,
                         vals.length);
        Arrays.sort(temp);

        return (temp);
    }

    public static void main(final String[] argv)
    {
        final List<String> list;
        final String[]     array;

        list = MyClass2.asSortedList("c", "a", "b");
        System.out.println(list);

        array = MyClass2.asSortedArray(String.class, "z", "y", "x");
        System.out.println(Arrays.deepToString(array));
    }
}


0 commentaires

0
votes

La contrainte de type que vous souhaitez sur la variable ne peut pas être exprimée directement. Vous pouvez introduire un nouveau type pour combler le problème. XXX

Cependant, il n'ya pas de point à être extrêmement de type sûr dans une pièce de code privée. Generic est là pour vous aider à clarifier vos types, de ne pas les obscurcer.


0 commentaires