2008-11-14 5 views
27

Während der Navigation der Methodenklasse bin ich auf die Funktion isBridge() gestoßen, von der javadoc sagt, dass sie nur dann wahr ist, wenn die Java-Spezifikation die Methode als wahr deklariert.Was java.lang.reflect.Method.isBridge() verwendet für?

Bitte helfen Sie mir zu verstehen, wofür diese verwendet wird? Kann eine benutzerdefinierte Klasse ihre Methode bei Bedarf als Bridge deklarieren?

Antwort

27

Eine Bridge-Methode kann vom Compiler erstellt werden, wenn ein parametrisierter Typ erweitert wird, dessen Methoden Parameter parametrisiert haben.

Sie können in dieser Klasse BridgeMethodResolver eine Möglichkeit finden, die tatsächliche Methode durch eine "Bridge-Methode" verwiesen werden.

Siehe Create Frame, Synchronize, Transfer Control:

Als Beispiel für eine solche Situation, die Erklärungen berücksichtigen:

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

Jetzt, da ein Aufruf

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

Das Löschen der aktuellen Methode aufgerufen wird D.id(String) unterscheidet sich in seiner Signatur von der Deklaration der Kompilierzeitmethode C.id(Object). Ersteres nimmt ein Argument vom Typ String, während letzteres ein Argument vom Typ Object annimmt. Der Aufruf schlägt mit einer ClassCastException fehl, bevor der Hauptteil der Methode ausgeführt wird.

Solche Situationen können nur auftreten, wenn das Programm eine ungeprüfte Warnung auslöst (§5.1.9).

Implementierungen können diese Semantik durch Erstellen von Bridge-Methoden erzwingen. Im obigen Beispiel würde die folgende Brücke Methode in der Klasse D erstellt werden:

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

Dies ist die Methode, die tatsächlich durch die virtuelle Java-Maschine in Reaktion auf den Aufruf c.id(new Object()) oben gezeigt aufgerufen werden würde, und es wird ausgeführt, die Besetzung und scheitern, wie erforderlich.

Siehe auch Bridge:

wie im Kommentar, Brücken genannten Methoden sind auch erforderlich für covariant zwingende:

  • In Java 1.4 und früher, kann eine Methode eine andere außer Kraft setzen, wenn Die Signaturen stimmen exakt mit überein.
  • In Java 5 kann ein Verfahren eines anderes außer Kraft setzen, wenn die Argumente genau passen, aber der Rückgabetyp des übergeordneten Verfahrens, wenn es ein Subtyp des Rückgabetypen des anderen Verfahrens.

Typischerweise wird ein Verfahren Object clone() von einem MyObject clone() außer Kraft gesetzt werden kann, sondern eine Brücke Methode wird vom Compiler generiert werden:

public bridge Object MyObject.clone(); 
+2

Auch ohne Generika sind Bridge-Methoden für kovariante Rückgabetypen notwendig. –

+0

BridgeMethodResolver Link ist kaputt :( – BrunoJCM

+0

@BrunoJCM good catch. Ich habe den Link wiederhergestellt (die Klasse wurde aus dem Projekt 'org.springframework.core' in das Projekt' spring-framework' verschoben: https://fisheye.springsource.org /browse/spring-framework/org.springframework.core/src/main/java/org/springframework/core/BridgeMethodResolver.java#rdc41daa3db350ef9a4b14ef1d750d79cb22cf431) – VonC

3

Das Beispiel gibt (von der JLS zitiert) macht es klingt gezeigt wie Bridge-Methoden werden nur in Situationen verwendet, in denen Rohtypen verwendet werden.Da dies nicht der Fall ist, dachte ich, ich würde ein Beispiel heranziehen, in dem Bridge-Methoden für vollständig typengleichen generischen Code verwendet werden.

Betrachten Sie die folgende Schnittstelle und Funktion:

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); 
} 

Wenn Sie diesen Code in der folgenden Art und Weise verwendet werden, eine Brücke Methode verwendet wird:

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

Nach dem Löschen der Function Schnittstelle enthält die Methode apply(Object)Object (was Sie durch Dekompilieren des Bytecodes bestätigen können). Wenn Sie sich den dekompilierten Code für applyFunc ansehen, sehen Sie natürlich, dass er einen Aufruf an apply(Object)Object enthält. Object ist die Obergrenze seiner Typvariablen, daher ist keine andere Signatur sinnvoll. Wenn eine anonyme Klasse mit der Methode apply(String)String erstellt wird, implementiert sie die Schnittstelle Function nicht, wenn keine Bridge-Methode erstellt wird Die Bridge-Methode ermöglicht allen generisch typisierten Code, diese Function Implementierung zu verwenden.

Interessanterweise nur, wenn die Klasse einige andere Schnittstelle mit der Unterschrift apply(String)String und nur dann durchgeführt, wenn das Verfahren über eine Referenz dieser Schnittstelle Typ hieß würde der Compiler jemals einen Anruf mit dieser Signatur emittieren.

Auch wenn ich den folgenden Code haben:

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

Der Compiler noch einen Aufruf an apply(Object)Object emittiert.

Es ist eigentlich eine andere Art und Weise, den Compiler zu erhalten apply(String)String zu nennen, aber es nutzt die magische Art zu einer anonymen Klasse Schöpfung Ausdruck zugeordnet, die gelegt werden kann nicht anders geschrieben:

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

Ein weiterer Fall I stolpered across hat nichts mit generics zu tun:

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