52 votes

Pourquoi pas un type Java paramètre a une limite inférieure?

Je suppose que vous ne pouvez pas lier un Java génériques type de paramètre à une limite inférieure (c'est à dire à l'aide de l' super mot-clé). J'ai été lire ce que le Angelika Langer Génériques FAQ avaient à dire sur le sujet. Ils disent que cela vient essentiellement vers le bas pour une limite inférieure d'être inutile ("parler").

Je ne suis pas convaincu. Je peux imaginer une utilisation pour eux pour vous aider à être plus souples pour les appelants d'une bibliothèque méthode qui produit typé résultat. Imaginez une méthode qui a créé un tableau de la liste de l'utilisateur spécifié la taille et le remplit avec la chaîne vide. Une simple déclaration serait

public static ArrayList<String> createArrayListFullOfEmptyStrings(int i);

Mais c'est inutilement restrictive pour vos clients. Pourquoi ne peuvent-ils invoquer votre méthode comme ceci:

//should compile
List<Object> l1 = createArrayListFullOfEmptyStrings(5); 
List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);
List<String> l3 = createArrayListFullOfEmptyStrings(5);

//shouldn't compile
List<Integer> l4 = createArrayListFullOfEmptyStrings(5);

À ce point, je serais tenté d'essayer la définition suivante:

public static <T super String> List<T> createArrayListFullOfEmptyStrings(int size) {
  List<T> list = new ArrayList<T>(size);
  for(int i = 0; i < size; i++) {
     list.add("");
  }
  return list;
}

Mais il ne compile pas; l' super mot-clé est illégal dans ce contexte.

Est mon exemple ci-dessus est un mauvais exemple (en ignorant ce que je dis ci-dessous)? Pourquoi n'est-il pas une limite inférieure utile ici? Et si il serait utile, ce qui est la vraie raison pour laquelle il n'est pas permis en Java?

P. S.

Je sais qu'une meilleure organisation pourrait être quelque chose comme ceci:

public static void populateListWithEmptyStrings(List<? super String> list, int size);

List<CharSequence> list = new ArrayList<CharSequence>();
populateListWithEmptyStrings(list, 5);

Pouvons-nous pour le but de cette question de prétendre qu'en raison d'une exigence, nous avons besoin de faire les deux opérations en un seul appel de méthode?

Modifier

@Tom G (à juste titre) demande quels sont les avantages d'avoir un List<CharSequence> sur un List<String>. Pour l'un, personne n'a dit que la liste retournée est immuable, voici donc un avantage:

List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);
l2.add(new StringBuilder("foo").append("bar"));

15voto

Bert F Points 27237

Fondamentalement, ce n'est pas assez utile.

Je pense que votre exemple souligne le seul avantage d'une limite inférieure, une caractéristique de la FAQ appels Restricted Instantiation:

La ligne de fond est: tout ce qu'un "super" lié achèteriez-vous est la restriction que seulement aux supertypes de Nombre peuvent être utilisés comme arguments de type. ....

Mais comme les autres postes, l'utilité même de cette fonctionnalité peut être limitée.

En raison de la nature de polymorphisme et de la spécialisation, les limites supérieures sont beaucoup plus utiles que les limites inférieures décrite par la FAQ (Accès Aux Membres Non Statique et Type d'Effacement). Je soupçonne la complexité introduite par les limites inférieures ne sont pas en vaut sa valeur limitée.


OP: je tiens à ajouter que je pense que vous n'avez montrer que c'est utile, mais pas assez utile. Venir avec de l'irréfutable tueur de cas d'utilisation et je vais revenir la JSR. :-)

10voto

irreputable Points 25577

la spec ne parle de limites inférieures des paramètres de type, par exemple

4.10.2

une variable de type direct supertype de sa limite inférieure.

5.1.10

une nouvelle variable de type ... dont la limite inférieure

Il apparaît qu'une variable de type a seulement une (non-nulle) limite inférieure si c'est la forme synthétique comme le résultat de générique de capture. Et si la langue permettent d'abaisser les limites sur tous les paramètres de type? Probablement, il ne veut pas causer beaucoup de problèmes, et il est exclu que pour garder les génériques de plus simple (enfin ...) de mise à Jour , il est dit que théorique enquête de la baisse des délimitée paramètres de type n'est pas complètement réalisée.

Mise à jour: un papier affirmant les limites inférieures sont ok: "Java Type Infererence Est Cassé: Pouvons-Nous Résoudre Ce problème", par Daniel Smith

RÉTRACTER: l'argument est faux. OP exemple est légitime.

Votre exemple n'est pas très convaincant. D'abord il n'est pas sécurisé. La liste retournée est en effet un List<String>, il est dangereux d'en faire un autre type. Supposons que votre code compile:

    List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);

ensuite, nous pouvons ajouter de Chaîne non, ce qui est faux

    CharSequence chars = new StringBuilder();
    l2.add(chars); 

Bien un List<String> n'est pas, mais un peu comme une liste de CharSequence. Votre besoin peut être résolu par l'utilisation générique:

public static  List<String> createArrayListFullOfEmptyStrings(int size)  

// a list of some specific subtype of CharSequence 
List<? extends CharSequence> l2 = createArrayListFullOfEmptyStrings(5);

// legal. can retrieve elements as CharSequence
CharSequence chars = l2.get(0);

// illegal, won't compile. cannot insert elements as CharSequence
l2.add(new StringBuilder());

2voto

Costi Ciudatu Points 13020

Supposons que c'était légal d'écrire:

public static <T super String> List<T> createArrayListFullOfEmptyStrings(int size) {...}

Mais maintenant, comment vous attendez-vous à ce à compiler:

List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);

La signature de la méthode ci-dessus , seuls les états qu'il sera de retour d'un super-type de Chaîne. Cela ne signifie pas que vous pouvez supposer ceux-ci seront tous CharSequence objets. Ils peuvent être de plain Object des cas. Seulement votre nom de la méthode dit quelque chose "...EmptyStrings". La signature de la méthode n'aide pas le compilateur beaucoup. Par conséquent, si ce serait possible de le faire, il serait tout de vous forcer à utiliser uniquement la valeur retournée comme List<Object>, il serait donc inutile.

EDIT: Les commentaires me prouver le contraire. :)

0voto

Tom G Points 5727

Quels sont les avantages de taper la Liste vous donner à ce point? Lorsque vous parcourez la collection en retour, vous devriez toujours être en mesure de faire ce qui suit:

for(String s : returnedList) {
CharSequence cs = s;
//do something with your CharSequence
}

-2voto

paulmurray Points 1764

Hmm, ok - allons travailler avec ce. Vous définissez une méthode:

public static <T super String> List<T> createArrayListFullOfEmptyStrings(int size) {

Qu'est-ce que cela signifie? Cela signifie que si j'appelle votre méthode, puis-je obtenir une liste de certains super-classe de la Chaîne. Peut-être qu'il renvoie une liste de Chaîne de caractères. Peut-être qu'il renvoie une liste d'Objets. Je ne sais pas.

Cool.

List<Object> l1 = createArrayListFullOfEmptyStrings(5);

Selon vous, que devrait compiler. Mais ce n'est pas juste! Je peux mettre un Entier dans une liste d'Objet - l1.add(3) . Mais si vous êtes de retour d'une liste de Chaîne de caractères, puis ce que devrait être illégal.

List<String> l3 = createArrayListFullOfEmptyStrings(5);

Selon vous, que devrait compiler. Mais ce n'est pas juste! l3.get(1) doit toujours retourner une Chaîne de caractères ... mais cette méthode peut avoir renvoyé une liste d'Objet, ce qui signifie que l3.(1) pourrait être un nombre Entier.

La seule chose qui fonctionne est

List<? super String> l5 = createArrayListFullOfEmptyStrings(5);

Tout ce que je sais, c'est que je peux appeler l4.put("foo"), et je peux obtenir de l' Object o = l4.get(2) .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X