Mécanisme d’effacement et limitations #
Le mécanisme d’effacement (appelé erasure en anglais) est la technique employée depuis Java 5 (2004) pour offrir les génériques. L’objectif était de rester compatible avec les anciennes versions de Java (dont les collections).
La transformation des déclarations génériques est réalisée à la compilation. A l’exécution, une instance ne préserve pas d’information quant aux types réels des paramètres. Nous verrons les limitations que cela implique.
Le mécanisme est le suivant:
- suppression de la déclaration des paramètres
<T>
- remplacement des occurrences de
T
par le typeObject
- casting lors d’appels de méthodes
La déclaration de Box<T>
simplifiée:
|
|
et une utilisation quelconque:
|
|
seraient équivalentes, lors de la compilation, à les remplacer par:
|
|
et:
|
|
Conséquences #
Cette stratégie est efficace, mais elle comporte des défauts :
- les possibilités sont réduites
- les règles sont parfois difficiles à appréhender
Différents extraits des limitations #
Paramètres primitifs impossibles #
|
|
Instanciation impossible #
Effectivement, il est impossible de déterminer si un paramètre est instanciable (s’il s’agit d’une classe et non d’une interface ou d’une classe abstraite) et s’il existe un constructeur sans arguments.
|
|
Une solution reste cependant possible:
|
|
Perte du paramètre à l’exécution #
|
|
Ce qui rend parfois compliquée une redéfinition de la méthode equals
avec des types génériques.
Surcharge impossible #
Une autre conséquence est de rendre la surcharge impossible avec les génériques:
|
|
Le Raw
type
#
Lorsqu’un type générique est déclaré sans ses paramètres, on l’appelle un raw type
(traduisez pas type brut). Il est permis pour autoriser la compatibilité avec les anciennes versions de Java qui ne supportaient pas encore les génériques.
|
|
Evitez-les. Indiquez les paramètres entre chevrons.
|
|
Le danger est de permettre ce genre de bug:
|
|
Conclusion #
Ce type d’erreur est inhérent à la JVM et au bytecode Java. Ces limitations peuvent se rencontrer dans d’autres langages supportés par la JVM comme Scala ou Kotlin. Cependant, ces derniers offrent des mécanismes pour renforcer le système de typage en offrant une syntaxe permettant de connaître les paramètres d’un générique à l’exécution. Kotlin utilise les reified type parameters
et Scala peut le faire à l’aide des TypeTag
ou ClassTag
implicites.
Approfondissement des restrictions en Java : docs.oracle.com .