2008-11-14 7 views
27

Lors de la navigation de la classe de méthode je suis tombé sur la fonction isBridge(), dont javadoc dit, que c'est vrai seulement si java spec déclare la méthode comme vraie.pour quoi java.lang.reflect.Method.isBridge() est-il utilisé?

S'il vous plaît aidez-moi à comprendre à quoi cela sert? Une classe personnalisée peut-elle déclarer sa méthode comme un pont si nécessaire?

Répondre

27

Une méthode de pont peut être créée par le compilateur lors de l'extension d'un type paramétré dont les méthodes ont des arguments paramétrés.

Vous pouvez trouver dans cette classe BridgeMethodResolver un moyen d'obtenir la méthode réelle référée par une «méthode de pont».

Voir Create Frame, Synchronize, Transfer Control:

À titre d'exemple d'une telle situation, tenez compte des déclarations:

class C<T> { abstract T id(T x); } 
class D extends C<String> { String id(String x) { return x; } } 

Maintenant, étant donné une invocation

C c = new D(); 
c.id(new Object()); // fails with a ClassCastException 

L'effacement de la méthode réelle invoquée , D.id(String) diffère dans sa signature de celle de la déclaration de méthode de compilation, C.id(Object). Le premier prend un argument de type String tandis que le second prend un argument de type Object. L'appel échoue avec une exception ClassCastException avant que le corps de la méthode soit exécuté.

De telles situations ne peuvent survenir que si le programme donne lieu à un avertissement non contrôlé (§5.1.9).

Les implémentations peuvent appliquer ces sémantiques en créant des méthodes de pont. Dans l'exemple ci-dessus, la méthode de pont suivant serait créé en classe D:

Object id(Object x) { return id((String) x); } 

Ceci est la méthode qui serait effectivement invoqué par la machine virtuelle Java en réponse à l'appel c.id(new Object()) indiqué plus haut, et il exécutera la distribution et échouer, au besoin.

Voir aussi Bridge:

comme mentionné dans le commentaire, les méthodes de pont sont également nécessaires pour covariant remplaçant:

  • En Java 1.4, et plus tôt, une méthode peut remplacer une autre si les signatures correspondent exactement à .
  • En Java 5, une méthode peut remplacer un autre si les arguments correspondent exactement mais le type de retour de la méthode redéfinie, si elle est un sous-type du type de retour de l'autre méthode.

En règle générale, une méthode Object clone() peut être remplacée par une MyObject clone(), mais une méthode de pont sera généré par le compilateur:

public bridge Object MyObject.clone(); 
+2

Même sans génériques, les méthodes de pont sont nécessaires pour les types de retour covariant. –

+0

Le lien BridgeMethodResolver est cassé :( – BrunoJCM

+0

@BrunoJCM bonne capture J'ai restauré le lien (la classe a été déplacée du projet 'org.springframework.core' au projet' spring-framework': https://fisheye.springsource.org /browse/spring-framework/org.springframework.core/src/main/java/org/springframework/core/BridgeMethodResolver.java#rdc41daa3db350ef9a4b14ef1d750d79cb22cf431) – VonC

3

L'exemple montré là (cité de la JLS) fait sonner comme Les méthodes de pont ne sont utilisées que dans les situations où des types bruts sont utilisés.Puisque ce n'est pas le cas, j'ai pensé que je ferais pipi avec un exemple où les méthodes de pont sont utilisées pour le code générique totalement correct.

Tenir compte de l'interface et la fonction suivante:

public static interface Function<A,R> { 
    public R apply (A arg); 
} 
public static <A, R> R applyFunc (Function<A,R> func, A arg) { 
    return func.apply(arg); 
} 

Si vous utilisez ce code de la manière suivante, une méthode de pont est utilisé:

Function<String, String> lower = new Function<String, String>() { 
    public String apply (String arg) { 
     return arg.toLowerCase(); 
    } 
}; 
applyFunc(lower, "Hello"); 

Après l'effacement, l'interface Function contient la méthode apply(Object)Object (que vous pouvez confirmer en décompilant le bytecode). Naturellement, si vous regardez le code décompilé pour applyFunc, vous verrez qu'il contient un appel à apply(Object)Object. Object est la limite supérieure de ses variables de type, donc aucune autre signature n'aurait de sens. Par conséquent, lorsqu'une classe anonyme est créée avec la méthode apply(String)String, elle n'implémente pas réellement l'interface Function à moins qu'une méthode de pontage ne soit créée. La méthode de pont permet à tout le code typé générique d'utiliser cette implémentation Function.

Fait intéressant, que si la classe a mis en œuvre une autre interface avec la signature apply(String)String et seulement si la méthode a été appelée par une référence de ce type d'interface serait le compilateur jamais émettre un appel avec cette signature.

Même si j'ai le code suivant:

Function<String, String> lower = ...; 
lower.apply("Hello"); 

Le compilateur émet toujours un appel à apply(Object)Object.

Il est en fait une autre façon d'obtenir le compilateur d'appeler apply(String)String, mais il profite du type magique attribué à une expression de création de classe anonyme qui ne peut autrement écrit:

new Function<String, String>() { 
    public String apply (String arg) { 
     return arg.toLowerCase(); 
    } 
}.apply("Hello"); 
0

Un autre cas, je trébuché à travers n'a rien à voir avec les génériques:

protected abstract class Super { 
    public void m() {} 
} 
public class Sub extends Super {} 
assert Sub.class.getMethod("m").isBridge();