web-dev-qa-db-fra.com

Pourquoi ne pas Java Les génériques prennent en charge les types primitifs?)

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

Par exemple, cela fonctionne bien:

List<Integer> foo = new ArrayList<Integer>();

mais ce n'est pas permis:

List<int> bar = new ArrayList<int>();
217
sgokhales

Les génériques dans Java sont une construction entièrement compile-temps - le compilateur convertit toutes les utilisations génériques en castes vers le bon type. Ceci est pour maintenir la compatibilité avec les versions précédentes JVM.

Cette:

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

se transforme en (à peu près):

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

Ainsi, tout ce qui est utilisé comme générique doit pouvoir être converti en objet (dans cet exemple, get(0) renvoie un Object), mais les types primitifs ne le sont pas. Donc, ils ne peuvent pas être utilisés dans les génériques.

222
thecoop

En Java, les génériques fonctionnent comme ils le font ... du moins en partie ... car ils ont été ajoutés au langage plusieurs années après sa conception.1. Les concepteurs de langage étaient astreints dans leurs options pour les génériques, car ils devaient concevoir un design compatible avec le langage existant et la bibliothèque de classe Java =.

D'autres langages de programmation (par exemple, C++, C #, Ada) permettent d'utiliser des types primitifs comme types de paramètres pour les génériques. Mais, inversement, la mise en œuvre de génériques (ou de types de modèles) par ces langages implique généralement la génération d’une copie distincte du type générique pour chaque paramétrage.


1 - La raison pour laquelle les génériques n’étaient pas inclus dans Java 1.0 était due à la pression temporelle. Ils estimaient devoir libérer rapidement le langage Java pour répondre aux nouvelles opportunités de marché offertes par les navigateurs Web. James Gosling a déclaré qu'il aurait aimé inclure des génériques s'ils en avaient eu le temps. Ce à quoi le langage Java aurait ressemblé si cela s'était produit est à deviner.

33
Stephen C

Dans Java, les génériques sont implémentés à l'aide de "Type erasure" pour la compatibilité descendante. Tous les types génériques sont convertis en objet au moment de l'exécution. par exemple,

public class Container<T> {

    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 la distribution appropriée pour assurer la sécurité du type.

Container<Integer> val = new Container<Integer>();
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?

La réponse est Object est la superclasse de tous les objets et peut représenter n’importe quel objet défini par l’utilisateur.

Puisque toutes les primitives n'héritent pas de "Object", nous ne pouvons donc pas l'utiliser comme type générique.

Pour votre information: le projet Valhalla tente de résoudre le problème ci-dessus.

7
Piyush Sagar

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

6
ZeissS

Conformément à Documentation Java , les variables de type générique ne peuvent être instanciées qu'avec des types de référence, pas des types primitifs.

Ceci est supposé entrer Java 10 sous Project Valhalla .

Dans Brian Goetz Document sur Etat de la spécialisation

Il y a un excellente explication sur la raison pour laquelle les génériques n'ont pas été pris en charge pour primitive. Et, comment cela sera implémenté dans les futures versions de Java.

L'implémentation effacée actuelle de Java qui produit une classe pour toutes les instanciations de référence et ne prend pas en charge les instanciations primitives. (Il s'agit d'une traduction homogène et la restriction selon laquelle les génériques de Java peuvent uniquement concerner des types de référence provient des limitations de traduction homogène par rapport au jeu de codes octets de la machine virtuelle, qui utilise différents codes octets pour les opérations sur les types de référence par rapport aux types primitifs.) Cependant, les génériques effacés dans Java fournissent à la fois une paramétrie comportementale (méthodes génériques) et une paramétrie de données (instanciations brutes et génériques de types génériques.)

...

une stratégie de traduction homogène a été choisie, dans laquelle les variables de type générique sont effacées jusqu'à leur limite, au fur et à mesure de leur incorporation dans du code intermédiaire. Cela signifie que, qu'une classe soit générique ou non, elle est toujours compilée en une seule classe, avec le même nom et dont les signatures de membre sont les mêmes. La sécurité de type est vérifiée lors de la compilation et le temps d'exécution est libre du système de type générique. Cela a à son tour imposé la restriction selon laquelle les génériques ne pouvaient fonctionner que sur les types de référence, car Object est le type le plus général disponible et ne s'étend pas aux types primitifs.

2
vinS