Pourquoi Java Generics ne prend-il pas en charge les types primitifs?

Pourquoi les génériques en Java fonctionnent-ils avec les classes mais pas avec les types primitifs?

Par exemple, cela fonctionne bien:

List foo = new ArrayList(); 

mais ce n’est pas autorisé:

 List bar = new ArrayList(); 

Les génériques en Java sont une construction entièrement à la compilation – le compilateur transforme tous les usages génériques en cast au bon type. Ceci permet de maintenir une compatibilité ascendante avec les exécutions JVM précédentes.

Ce:

 List list = new ArrayList(); list.add(new ClassA()); ClassA a = list.get(0); 

se transforme en (grossièrement):

 List list = new ArrayList(); list.add(new ClassA()); ClassA a = (ClassA)list.get(0); 

Donc, tout ce qui est utilisé comme générique doit être convertible en Object (dans cet exemple, get(0) retourne un Object ) et les types primitifs ne le sont pas. Ils ne peuvent donc pas être utilisés en génériques.

En Java, les génériques fonctionnent comme ils le font … du moins en partie … car ils ont été ajoutés à la langue plusieurs années après la conception de la langue 1 . Les concepteurs de langages étaient limités dans leurs options pour les génériques en ayant à présenter une conception rétrocompatible avec le langage existant et la bibliothèque de classes Java .

D’autres langages de programmation (par exemple, C ++, C #, Ada) permettent d’utiliser des types primitifs comme types de parameters pour les génériques. Mais le revers de la médaille est que l’implémentation de ces génériques (ou types de modèles) implique généralement la génération d’une copie distincte du type générique pour chaque paramétrage de type.


1 – La raison pour laquelle les génériques n’étaient pas inclus dans Java 1.0 était la pression temporelle. Ils ont estimé qu’ils devaient rapidement publier le langage Java pour répondre aux nouvelles opportunités du marché présentées par les navigateurs Web. James Gosling a déclaré qu’il aurait aimé inclure les médicaments génériques s’ils en avaient eu le temps. À quoi aurait ressemblé le langage Java si cela s’était produit?

Les collections sont définies pour exiger un type dérivé de java.lang.Object . Les types de base ne font tout simplement pas cela.

En java, les génériques sont implémentés en utilisant “Effacement de type” pour une compatibilité descendante. Tous les types génériques sont convertis en Object à l’exécution. par exemple,

 public class Container { private T data; public T getData() { return data; } } 

sera vu à l’exécution comme,

 public class Container { private Object data; public Object getData() { return data; } } 

Le compilateur est responsable de fournir une dissortingbution appropriée pour assurer la sécurité du type.

 Container val = new Container(); Integer data = val.getData() 

va devenir

 Container val = new Container(); Integer data = (Integer) val.getData() 

Maintenant, la question est pourquoi “Object” est choisi comme type à l’exécution?

Answer is Object est la super-classe de tous les objects et peut représenter n’importe quel object défini par l’utilisateur.

Puisque toutes les primitives n’héritent pas de ” Object “, nous ne pouvons pas l’utiliser comme type générique.

FYI: Le projet Valhalla tente de résoudre le problème ci-dessus.

Selon la documentation Java , les variables de type génériques ne peuvent être instanciées qu’avec des types de référence, pas des types primitifs.

Ceci est censé venir dans Java 10 dans le cadre du projet Valhalla .

Dans l’article de Brian Goetz sur l’ état de la spécialisation

Il y a une excellente explication sur la raison pour laquelle les génériques n’étaient pas pris en charge pour les primitives. Et comment cela sera implémenté dans les futures versions de Java.

Implémentation effacée de Java qui produit une classe pour toutes les instanciations de référence et ne prend pas en charge les instanciations primitives. (Ceci est une traduction homogène, et la ressortingction selon laquelle les génériques de Java ne peuvent couvrir que les types de référence provient des limitations de la traduction homogène par rapport au jeu de bytecode de la JVM, qui utilise des bytecodes différents pour les types de référence et les types primitifs.) Cependant, les génériques effacés en Java fournissent à la fois une paramésortingsation comportementale (méthodes génériques) et une paramésortingsation des données (instanciations brutes et génériques des types génériques).

une stratégie de traduction homogène a été choisie, dans laquelle les variables de type génériques sont effacées à mesure qu’elles sont incorporées dans le bytecode. Cela signifie que si une classe est générique ou non, elle comstack toujours en une seule classe, avec le même nom, et dont les signatures des membres sont les mêmes. La sécurité de type est vérifiée au moment de la compilation et le temps d’exécution est libre du système de type générique. À son tour, cela imposait la ressortingction selon laquelle les génériques ne pouvaient fonctionner que sur les types de référence, puisque Object est le type le plus général disponible, et qu’il ne s’étend pas aux types primitifs.