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: p> à 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. P> Ce qui suit est le code que j'ai, mais je Impossible de trouver le bon Mojo à mettre pour le type de variable. p> erreur sur la ligne de déclaration de variable: p> @mark: strong> 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: p> erreur sur Ajouter une ligne: p> erreur sur ligne de tri: p> conclusion: strong> p> 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: P> 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. p>
blockQuote> 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. P> p>
7 Réponses :
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 afin de ramener ce retour à ce que vous essayez de faire ici, une instance de 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 non. La vraie solution consiste à faire et retirez la déclaration du paramètre de type de niveau de niveau t code> 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 code>, quel est le type noional de t code> dans le contexte de la déclaration d'attribut?) P > myClass code> 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é MyClass code> qui détient (disons) integer code> objets et une contenant string < / Code> Objets? P> getsortedlist () code> ne peut pas savoir quel type réel est lié à son type de retour.) P> myClass code> une classe générique qui déclare le paramètre type t code>; E.g. p> t code> à partir des deux méthodes. P> P>
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 code> code> 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
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");
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
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);
}
}
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).
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 Un test rapide en utilisant ce qui suit montre que pour les classes qui implémentent comparables (comme entier et une chaîne) code> comme quelque chose que quelque chose contenant des choses que vous connaissez est comparable code>. 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: myClass code> se comporte comme prévu, mais Lancer une erreur de compilation pour les classes qui ne mettent pas en œuvre comparable code>: p>
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.
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;
}
}
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));
}
}
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. 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. p> p>
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.