Frage

IMY -Frage betrifft das Verhalten des Typs des Typs mit dynamischem Proxy und Java -Generika. Insbesondere möchte ich ein Servelet -Objekt mit dynamischem Proxy instrumentieren. Für eine bessere Wiederverwendbarkeit habe ich eine generische Code -Vorlage für das Erstellen von Proxy -Objekten wie unten übernommen.

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

Hier ist es meine konkrete Servelet -Implementierungsklasse, die MyServelet -Schnittstelle implementiert. Wenn ich jedoch die obige Methode ausführe, druckt sie aus

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

Deshalb frage ich mich, was mit der Typ -Casting -Erklärung im Code -Snippet passiert ist. Es scheint, als ob es leise gescheitert ist, da der Stellvertreter nicht in MyServeletImplementation gegossen wurde, aber es hat auch ClassCastException nicht geworfen. Kann mir jemand etwas Licht darauf werfen? Vielen Dank!

War es hilfreich?

Lösung

In der tatsächlichen kompilierten Bytecode der Methode fand keine Gips statt Typlase.

Beim Generieren von Bytecode behandelt der Compiler eine Variable eines Parametertyps wie den gleichen Typ wie die Obergrenze des Parametertyps oder oder Object Wenn der Typ unbegrenzt ist. Also wenn T in Ihrer Methode hatte die Einschränkung <T extends MyServelet>, der Compiler hätte behandelt proxy Als Variable des Typs MyServelet, und fügte einen Guss ein. Allerdings da T ist unbegrenzt, es wird als Variable des Typs behandelt Object - Also keine Besetzung.

Andere Tipps

Der Punkt des dynamischen Proxy ist, dass Sie sich nicht um die tatsächliche Klasse des Stellvertreters kümmern, der zurückgegeben wird. Sie kümmern sich nur darum, dass es alle gewünschten und spezifizierten Schnittstellen implementiert.

Die Javadocs für newProxyInstance Zustand:

Kehrt zurück:

Eine Proxy -Instanz mit dem angegebenen Aufrufhandler einer Proxy -Klasse, die vom angegebenen Klassenlader definiert wird und die angegebenen Schnittstellen implementiert

So, newProxyInstance zurückgegeben eine Instanz von com.sun.proxy.$Proxy0 (Was auch immer das ist, wir kümmern uns nicht wirklich darum), aber es hat auch dafür gesorgt, dass es ein ist MyServelet. Sie sollten in der Lage sein, es zu geben MyServelet ohne ein ClassCastException, Weil newProxyInstance Erstellt die Klasse, um diese Schnittstelle zu implementieren new Class[]{MyServelet.class}.

Damit das Typ Casting nicht gescheitert ist, muss Java Generics das geschmückt haben T ist MyServelet, nicht MyServeletImplementation. Vielleicht, wenn du angerufen hast instrument, Sie haben es so gemacht:

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

Also war die Besetzung zu MyServelet welches erfolgreich sein sollte und nicht zu MyServeletImplementation, was scheitern sollte.

Der Grund, warum Sie hinzufügen mussten @SuppressWarnings("unchecked") liegt daran, dass der Compiler versucht hat, Sie zu warnen, dass Sie etwas falsch gemacht haben. Durch das Hinzufügen der Unterdrückung sagten Sie dem Compiler, dass es Ihnen egal war, weil Sie wussten, was Sie taten. Vielleicht hätten Sie die Annotation nicht hinzufügen sollen, wenn Sie nicht verstanden haben, warum Sie die Warnung in erster Linie erhalten haben?

Hinweis: Die generische Besetzung T proxy = (T) wird in Object proxy = (Object) vom Compiler. ("Typ Löschen", wie in einer anderen Antwort erwähnt).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top