10
votes

Comment l'effacement Java affecte-t-il les matrices génériques?

J'étudie des génériques dans cette période et j'ai trouvé ce mystère pour moi.

Considérons la classe factice suivante: xxx

à cause de l'effacement , au moment de l'exécution, le type de retour T [] de la méthode Getarray () est transformé en un objet [], qui est totalement raisonnable pour moi.

Si nous accédons à cette méthode telle qu'elle est (c.getarray ()) Aucune exception n'est lancée, mais si nous essayons d'appeler des méthodes sur le tableau retourné, par exemple C.Array (). GetClass () ou si nous essayons d'accéder à un champ, par exemple C.GetARRAY () .Longueur, puis l'exception suivante est lancée:

Exception dans le fil "Main" Java.lang.classcastException: [Ljava.lang.Object; ne peut pas être coulé à [ljava.lang.Integer;

Pourquoi cette exception est-elle jetée? Pourquoi n'est-ce pas jeté aussi pour l'appel de C.GetARRAY () simple? Pourquoi essaie-t-il de lancer entier [] si nous appelons simplement getclass () ou d'accéder à la longueur? Sont getclass () et la longueur non disponibles aussi pour l'objet []?

Merci d'avance pour votre nombre (j'espère) et explicite (j'espère que cela aussi) réponses.


5 commentaires

Afin de désirer la valeur de c.getarray () , une référence à celle-ci doit être stockée temporairement sur la pile. Je peux imaginer que JLS dit - quelque part, toujours à la recherche - que cette variable temporaire doit être vérifiée pour voir s'il s'agit du type inersidé (puisque vous connaissez le type non alinéa).


En effet, cela fonctionne si vous faites la déséroferience dans une méthode comme statique Void FOO (conteneur C) {C.GETARRAY (). GetClass (); }


Il y a une différence intéressante dans le bytecode si vous changez vers : avec integer , il y a une vérification instruction (la raison du ClasscastException ); Avec l'objet , aucun Checkcast est ajouté. Compréhensible, puisque tous les t [] peuvent être distribués sur objet [] ; juste surprenant que cela entraîne différents bytecodes.


@Matsemann parce que je n'ai pas vraiment de réponse :) Je fais des observations.


La distribution à entier [] sur le site d'appel de getarray () n'est pas différent, linguistique, que la distribution à entier sur le site d'appel de get () . (Ceci, BTW, c'est pourquoi Collection.Tearray () Retours Objet [] plutôt que T [] - Il ne veut pas mentez-vous et dites qu'il retourne un entier [] quand il renvoie vraiment un objet [] .)


3 Réponses :


2
votes

La raison de l'exception est que le compilateur attend un entier [] code> mais reçoit un objet [] code>. Il a ajouté une distribution d'exécution - sur les sites d'appel de getarray code>. Ces moulages ont découvert le couché, le mannequin, sans effet dans votre constructeur.

Pour que ce soit correct, il faut la classe actuelle de T, afin de créer des instances. P>

(double[][][][][][]) Array.newInstance(double.class, 3, 3, 3, 3, 3, 6);


2 commentaires

Mais je ne peux pas comprendre pourquoi il ne se plaint pas de C.Getarray () mais cela fait pour C.GetARRAY (). GetClass (). Ce qui me conduit fou est que c.getarray () est bien alors que c.getarray (). GetClass () n'est pas. Pourquoi le compilateur ne se plaint que pour le second? Dans le cas de C.GetARRAY (), la distribution non fonctionnelle devrait également se produire.


Vous n'édorciez pas g.getarray ().



1
votes

Je n'ai pas pu trouver l'endroit exact dans les JLS qui dit que c'est le comportement, mais je pense que la raison est comme ceci:

L'expression: p>

      15: checkcast     #5                  // class "[Ljava/lang/Integer;"
      18: astore_1
      19: aload_1


3 commentaires

La mauvaise distribution se produit dans entier [] arr = (entier []) C.GETARRAY (); , non? Donc, si c.getarray (). Getclass () échoue, c.getarray () doit échouer de la même manière parce que la distribution est effectuée avant le getclass () < / Code> Invocation.


Non, je ne pense pas que oui - c'est le déséroférance de c.getarray () qui semble causer le problème. Par exemple, system.out.println (c.getarray ()) fonctionne bien; Mais cela invoque le system.out.println (objet) surcharge, qui ne nécessite pas la distribution.


C'est intéressant, merci. Si system.out.println (c.getarray ()) fonctionne bien parce que l'utilisation de l'objet ne serait pas la même pour c.getarray (). Getclass () ? Je veux dire, getclass () est une méthode d'objet, de sorte que cela devrait fonctionner de toute façon. Où suis-je tort?



1
votes

Lorsque vous faites un casting non sécurisé non sécurisé, il peut ne pas provoquer une exception quelque part. Vous n'êtes pas garanti d'obtenir une exception quelque part.

Dans ce cas, si vous obtenez une exception dépend de la question de savoir si le compilateur a inséré une distribution dans le code effacé pour lancer le résultat de l'appel à entier [] . Dans ce cas, il semble qu'un casting a été inséré dans les deuxième et troisième cas, mais pas le premier cas.

Dans chacun des trois cas, le compilateur est autorisé à insérer une distribution (car il est autorisé à supposer que le résultat est entier [] ou ne pas insérer une distribution (car l'expression est utilisée. de telle manière que nécessitent uniquement objet [] dans les trois). Insertion d'une mise en forme ou non à la mise en œuvre du compilateur particulier pour décider.

Pourquoi ce compilateur n'entraînerait-il pas de distribution dans le premier cas et insérerait-il une distribution dans les deuxième et troisième cas? Une explication évidente serait que dans le premier cas, le résultat est évidemment inutilisé, il est donc très simple de déterminer qu'un casting est inutile. Dans les deuxième et troisième cas, pour déterminer qu'une distribution est inutile nécessiterait de regarder la manière dont l'expression est utilisée pour voir que cela fonctionnera également avec objet [] ; Et c'est une analyse assez compliquée. Les auteurs du compilateur ont probablement opté pour une approche simple où ils ne sautent que lorsque le résultat n'est pas utilisé.

Un autre compilateur peut insérer des moulages dans les trois cas. Et un autre compilateur pourrait ne pas avoir de moulage dans les trois cas. Vous ne pouvez pas compter sur elle.


0 commentaires