Eh bien, la motivation (compatibilité descendante) est à la fois un avantage et un inconvénient. C'est un inconvénient car nous préférerions tous avoir des types réifiables, mais le prix à payer était élevé. Considérez les choix de conception en C #. Ils ont des types réifiables, mais maintenant ils ont des API en double. Imaginez donc une API Java où nous avions également des API en double pour chaque classe paramétrée. Maintenant, imaginez-vous porter des milliers de lignes de code des classes héritées vers les nouvelles classes génériques. Maintenant, qui ne considérerait pas les API en double comme un inconvénient? Mais bon, ils ont des types réifiables!
Ainsi, la motivation principale était "l'évolution, pas la révolution". Et logiquement, chaque décision a des compromis.
Outre les autres inconvénients mentionnés, nous pourrions également ajouter le fait que l'effacement de type peut être difficile à raisonner au moment de la compilation, car il n'est pas évident que certains types seront supprimés, ce qui conduit à des erreurs très étranges et difficiles à trouver.
L'existence de méthodes de pontage (ce compilateur de méthodes générées syntaxiquement pour conserver la compatibilité binaire) peut également être considérée comme un inconvénient. Et cela peut être précisément l'une des raisons des erreurs que j'ai mentionnées dans le paragraphe précédent.
Les inconvénients majeurs découlent du fait déjà évident qu'il existe une seule classe et non plusieurs classes pour les types génériques. Comme autre exemple, considérons que la surcharge d'une méthode avec la même classe générique échoue en Java:
public void doSomething(List<One>);
public void doSomething(List<Two>);
Quelque chose qui pourrait être considéré comme un inconvénient des types réifiables (au moins en C #) est le fait qu'ils provoquent une explosion de code . Par exemple, List<int>
est une classe, et a List<double>
est une autre totalement différente, car c'est un List<string>
et un List<MyType>
. Les classes doivent donc être définies au moment de l'exécution, ce qui provoque une explosion des classes et consomme des ressources précieuses lors de leur génération.
Concernant le fait qu'il n'est pas possible de définir un new T()
en Java, mentionné dans une autre réponse, il est également intéressant de considérer que ce n'est pas seulement une question d'effacement de type. Cela nécessite également l'existence d'un constructeur par défaut, c'est pourquoi C # nécessite pour cela une "nouvelle contrainte". (Voir Pourquoi le nouveau T () n'est pas possible en Java , par Alex Buckley).
T
s, vous obtenez une seule copie duClass<T>
code pour tous lesT
s; plus une copie supplémentaire pour chaque type de valeurT
réellement utilisé.L'inconvénient de l'effacement de type est que vous ne connaissez pas au moment de l'exécution le type du générique. Cela implique que vous ne pouvez pas leur appliquer de réflexion et que vous ne pouvez pas les instancier au moment de l'exécution.
Vous ne pouvez pas faire quelque chose comme ça en Java:
Il existe une solution de contournement pour cela, mais cela nécessite plus de code. L'avantage, comme vous l'avez mentionné, est la compatibilité descendante.
la source
Un autre avantage des génériques effacés est que les différents langages qui se compilent vers la JVM utilisent différentes stratégies pour les génériques, par exemple le site de définition de Scala contre la covariance du site d'utilisation de Java. Les génériques de type supérieur de Scala auraient également été plus difficiles à prendre en charge sur les types réifiés de .Net, car essentiellement Scala sur .Net a ignoré le format de réification incompatible de C #. Si nous avions des génériques réifiés dans la machine virtuelle Java, ces génériques réifiés ne seraient probablement pas adaptés aux fonctionnalités que nous aimons vraiment à propos de Scala, et nous serions coincés avec quelque chose de sous-optimal. Citant le blog d' Ola Bini ,
Personnellement, je ne considère pas la nécessité d'utiliser un
TypeTag
contexte lié à Scala pour les méthodes surchargées conflictuelles comme un inconvénient, car cela déplace les frais généraux et l'inflexibilité de la réification d'un global (programme entier et toutes les langues possibles) à un site d'utilisation par langue question qui est seulement le cas moins fréquemment.la source