Les collections Java ne stockent que des objets, et non des types primitifs ; cependant, nous pouvons stocker les classes d'enveloppe.
Pourquoi cette contrainte ?
Les collections Java ne stockent que des objets, et non des types primitifs ; cependant, nous pouvons stocker les classes d'enveloppe.
Pourquoi cette contrainte ?
C'était une décision de conception de Java, que certains considèrent comme une erreur. Les conteneurs veulent des objets et les primitives ne dérivent pas des objets.
Les concepteurs de .NET ont appris de la JVM et ont implémenté les types de valeurs et les génériques de telle sorte que la mise en boîte est éliminée dans de nombreux cas. Dans le CLR, les conteneurs génériques peuvent stocker des types de valeur en tant que partie de la structure sous-jacente du conteneur.
Java a choisi d'ajouter le support générique à 100% dans le compilateur sans support de la JVM. La JVM étant ce qu'elle est, elle ne supporte pas un objet "non-objet". Les génériques Java vous permettent de prétendre qu'il n'y a pas d'enveloppe, mais vous payez toujours le prix de la performance de la mise en boîte. Ceci est IMPORTANT pour certaines classes de programmes.
La boxe est un compromis technique, et j'ai le sentiment qu'il s'agit d'un détail de mise en œuvre qui s'infiltre dans le langage. L'autoboxing est un sucre syntaxique agréable, mais il est toujours une pénalité de performance. J'aimerais que le compilateur m'avertisse quand il fait de l'autoboxing. (Pour ce que j'en sais, il peut maintenant, j'ai écrit cette réponse en 2010).
Une bonne explication sur SO sur la boxe : Pourquoi certaines langues ont-elles besoin de Boxing et Unboxing ?
Et critique des génériques Java : Pourquoi certains prétendent-ils que la mise en œuvre des génériques par Java est mauvaise ?
À la décharge de Java, il est facile de regarder en arrière et de critiquer. La JVM a résisté à l'épreuve du temps et est une bonne conception à bien des égards.
Il ne s'agit pas d'une erreur, mais d'un compromis soigneusement choisi qui, selon moi, a très bien servi Java.
C'était une erreur suffisante pour que .NET en tire les leçons et implémente l'autoboxing dès le début, ainsi que les génériques au niveau de la VM sans surcharge de boxing. La tentative de correction de Java n'était qu'une solution au niveau de la syntaxe qui souffre toujours de l'impact sur les performances de l'autoboxing par rapport à l'absence totale de boxing. L'implémentation de Java a montré des performances médiocres avec les grandes structures de données.
@mrjoltcola : IMHO, la mise en boîte automatique par défaut est une erreur, mais il aurait dû y avoir un moyen de marquer les variables et les paramètres qui devraient automatiquement mettre en boîte les valeurs qui leur sont données. Même maintenant, je pense qu'il devrait y avoir un moyen ajouté pour spécifier que certaines variables ou paramètres devraient pas accepter les valeurs nouvellement encadrées [par exemple, il devrait être légal de faire passer Object.ReferenceEquals
références de type Object
qui identifient les entiers encadrés, mais il ne devrait pas être légal de passer une valeur entière]. L'auto-unboxing de Java est, à mon avis, tout simplement désagréable.
Rend la mise en œuvre plus facile. Les primitives Java n'étant pas considérées comme des objets, il faudrait créer une classe de collection distincte pour chacune de ces primitives (pas de code modèle à partager).
Vous pouvez le faire, bien sûr, il suffit de voir GNU Trove , Primitives Apache Commons o HPPC .
À moins que vous n'ayez de très grandes collections, la surcharge des wrappers n'est pas suffisamment importante pour que les gens s'en préoccupent (et lorsque vous avez de très grandes collections primitives, vous devriez peut-être faire l'effort d'utiliser/construire une structure de données spécialisée pour elles).
C'est une combinaison de deux faits :
int
n'est pas un Object
)List<?>
est en réalité un List<Object>
au moment de l'exécution)Comme ces deux affirmations sont vraies, les collections Java génériques ne peuvent pas stocker directement les types primitifs. Pour des raisons de commodité, l'autoboxing est introduit pour permettre aux types primitifs d'être automatiquement mis en boîte comme des types de référence. Cependant, ne vous y trompez pas, les collections stockent toujours des références d'objets.
Cela aurait-il pu être évité ? Peut-être.
int
es un Object
Dans ce cas, il n'est pas nécessaire d'utiliser des types de boîtes.Il y a le concept de auto-boxing et l'auto-déballage. Si vous tentez de stocker un int
dans un List<Integer>
le compilateur Java le convertira automatiquement en un fichier de type Integer
.
Mais c'est une question de compilation, un sucre syntaxique sans avantage pour les performances. Le compilateur Java utilise des boîtes automatiques, d'où la pénalité de performance par rapport aux implémentations VM comme .NET, dont les génériques n'impliquent pas de boîtes.
@mrjoltcola : Quel est votre point de vue ? Je ne faisais que partager des faits, sans argumenter.
Ce n'est pas vraiment une contrainte, n'est-ce pas ?
Imaginez que vous vouliez créer une collection qui stocke des valeurs primitives. Comment écririez-vous une collection qui peut stocker des int, des float ou des char ? Il est fort probable que vous vous retrouviez avec plusieurs collections, et que vous ayez besoin d'une intlist, d'une charlist, etc.
En tirant parti de la nature orientée objet de Java, lorsque vous écrivez une classe de collection, elle peut stocker n'importe quel objet, de sorte que vous n'avez besoin que d'une seule classe de collection. Cette idée, le polymorphisme, est très puissante et simplifie considérablement la conception des bibliothèques.
"Comment écrivez-vous une collection qui peut stocker soit int, soit float, soit char ?" - Avec des génériques / templates correctement implémentés comme les autres langages qui ne paient pas la pénalité de prétendre que tout est un objet.
En six ans de Java, je n'ai pratiquement jamais voulu stocker une collection de primitives. Même dans les rares cas où je l'ai voulu, le temps et l'espace supplémentaires nécessaires pour utiliser les objets de référence ont été négligeables. En particulier, je trouve que beaucoup de gens pensent qu'ils veulent Map<int,T>, oubliant qu'un tableau fait très bien l'affaire.
@DJClayworth Cela ne fonctionne bien que si les valeurs des clés ne sont pas éparses. Bien sûr, vous pourriez utiliser un tableau auxiliaire pour garder la trace des clés, mais cela a ses propres problèmes : un accès relativement efficace nécessiterait de garder les deux tableaux triés en fonction de l'ordre des clés pour permettre une recherche binaire, ce qui à son tour rendrait l'insertion et la suppression inefficaces à moins que l'insertion/la suppression ne soit structurée de telle sorte que les éléments insérés soient susceptibles de se retrouver là où se trouvait un élément précédemment supprimé et/ou que certains tampons soient intercalés dans les tableaux, etc. Il existe des ressources disponibles, mais ce serait bien de les avoir dans Java lui-même.
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.
3 votes
Cette contrainte craint lorsque vous traitez des primitives et que vous voulez utiliser des files d'attente pour envoyer et que vos taux d'envoi sont très rapides. Je suis actuellement confronté au problème de l'envoi automatique qui prend trop de temps.
1 votes
Techniquement, les types primitifs sont des objets (des instances singletons pour être exact), ils ne sont simplement pas définis par un objet
class
mais plutôt par la JVM. L'instructionint i = 1
définit un pointeur vers l'instance singleton de l'objet qui définitint
dans la JVM, définie à la valeur1
défini quelque part dans la JVM. Oui, les pointeurs en Java - c'est simplement abstrait de vous par l'implémentation du langage. Les primitives ne peuvent pas être utilisées en tant que génériques, car le langage prévoit que tous les types génériques doivent être de type supérieur.Object
- d'où la raisonA<?>
compile enA<Object>
au moment de l'exécution.2 votes
@RobertEFry les types primitifs sont pas objets en Java, donc tout ce que vous avez écrit sur les instances singleton et autres est fondamentalement faux et confus. Je vous suggère de lire le "Types, valeurs et variables" chapitre de la spécification du langage Java, qui définit ce qu'est un objet : "Un objet (§4.3.1) est une instance créée dynamiquement d'un type de classe ou un tableau créé dynamiquement."