Question

La question IMY concerne le comportement de la coulée de type avec des génériques dynamiques et java. Plus précisément, je souhaite instrument un objet Servelet en utilisant un proxy dynamique. Pour une meilleure réutilisabilité, j'ai adopté un modèle de code générique pour créer des objets proxy comme ci-dessous.

@SuppressWarnings("unchecked")
public static <T> T instrument(final T aT) {
    T proxy = (T) Proxy.newProxyInstance(aT.getClass().getClassLoader(), new Class[]{MyServelet.class}, new InvocationHandler() {
        @Override
        public Object invoke(Object aProxy, Method aMethod, Object[] aArgs) throws Throwable {
        ..... instrumentation logic goes here
        }
    });
     System.out.println("proxy class " + proxy.getClass());
     System.out.println("input class " + aT.getClass());
     return proxy;
}

Ici, c'est ma classe d'implémentation CELVELET en béton qui implémente l'interface MyServelet. Cependant, si j'exécute la méthode ci-dessus, il imprime

proxy class class com.sun.proxy.$Proxy0
input class class MyServeletImplementation

Je me demande donc ce qui est arrivé à la déclaration de casting de type dans l'extrait de code. Il semble que cela échoue tranquillement car le proxy n'a pas été jeté à MyServeleTIMPlementation, mais cela n'a pas non plus lancé ClassCastException. Quelqu'un peut-il me faire la lumière à ce sujet? Merci!

Était-ce utile?

La solution

Aucune distribution n'a eu lieu dans le code bytecode compilé de la méthode, en raison de Effacement de type.

Lors de la génération de bytecode, le compilateur traite toute variable d'un type de paramètre comme ayant le même type que la limite supérieure de ce type de paramètre, ou Object Si le type est illimité. Donc si T dans votre méthode avait la contrainte <T extends MyServelet>, le compilateur aurait traité proxy comme variable de type MyServelet, et inséré un casting. Cependant, comme T est illimité, il est traité comme une variable de type Object - Ainsi, pas de casting.

Autres conseils

Le point du proxy dynamique est que vous ne vous souciez pas de la classe réelle du proxy qui est retourné. Vous vous souciez simplement qu'il implémente toutes les interfaces souhaitées et spécifiées.

Les javadocs pour newProxyInstance Etat:

Retour:

une instance proxy avec le gestionnaire d'invocation spécifié d'une classe proxy définie par le chargeur de classe spécifié et qui implémente les interfaces spécifiées

Alors, newProxyInstance retourné une instance de com.sun.proxy.$Proxy0 (Quoi que ce soit, nous ne nous en soucions pas vraiment), mais cela s'est également assuré que ce soit un MyServelet. Vous devriez pouvoir le lancer MyServelet sans un ClassCastException, car newProxyInstance a créé la classe pour implémenter cette interface, et vous avez spécifié qu'il devrait en transmettre new Class[]{MyServelet.class}.

Pour que le casting de type n'ait pas échoué, les génériques Java doivent avoir déduit que T est MyServelet, ne pas MyServeletImplementation. Peut-être que quand tu as appelé instrument, vous l'avez fait comme ceci:

MyServelet proxy = YourClass.instrument(new MyServeletImplementation());

Alors le casting était de MyServelet qui devrait réussir, et non MyServeletImplementation, qui devrait échouer.

La raison pour laquelle vous deviez ajouter @SuppressWarnings("unchecked") C'est parce que le compilateur essayait de vous avertir que vous faisiez quelque chose de mal. En ajoutant la suppression, vous avez dit au compilateur que vous ne s'en fichiez pas parce que vous saviez ce que vous faisiez. Peut-être que vous n'auriez pas dû ajouter l'annotation si vous ne savez pas pourquoi vous obteniez l'avertissement en premier lieu?

Astuce: le casting générique T proxy = (T) se transforme en Object proxy = (Object) par le compilateur. ("Type Erasure" comme mentionné dans une autre réponse).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top