Domanda

La domanda imy riguarda il comportamento del casting di tipo con proxy dinamico e generici Java. Più specificamente, voglio strumentare un oggetto Servelet usando il proxy dinamico. Per una migliore riusabilità, ho adottato alcuni modelli di codice generico per la creazione di oggetti proxy come di seguito.

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

Qui T è la mia classe di implementazione Servelet concreta che implementa l'interfaccia MyServelet. Tuttavia, se eseguo il metodo sopra, stampa

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

Quindi mi chiedo cosa sia successo alla dichiarazione di casting nel frammento di codice. Sembra che non sia fallito in silenzio poiché il proxy non è stato lanciato su MyServeletImplementation, ma non ha anche lanciato ClasscastException. Qualcuno può farmi luce su questo? Grazie!

È stato utile?

Soluzione

Nessun cast ha avuto luogo nell'effettivo bytecode compilato del metodo, a causa di Digitare cancellazione.

Quando si genera bytecode, il compilatore tratta qualsiasi variabile di un tipo di parametro con lo stesso tipo di tipo superiore di quel parametro, o Object Se il tipo è illimitato. Quindi se T Nel tuo metodo aveva il vincolo <T extends MyServelet>, il compilatore avrebbe trattato proxy Come variabile di tipo MyServelet, e ha inserito un cast. Tuttavia, come T è illimitato, è trattato come una variabile di tipo Object - Quindi, nessun cast.

Altri suggerimenti

Il punto del proxy dinamico è che non ti interessa la classe effettiva del proxy che viene restituito. Ti interessa solo che implementa tutte le interfacce desiderate e specificate.

I Javadocs per newProxyInstance stato:

Ritorna:

un'istanza proxy con il gestore di invocazione specificato di una classe proxy definita dal caricatore di classe specificato e che implementa le interfacce specificate

Così, newProxyInstance restituito un'istanza di com.sun.proxy.$Proxy0 (Qualunque cosa sia, non ci interessa davvero), ma si è anche assicurato che fosse un MyServelet. Dovresti essere in grado di lanciarlo MyServelet senza un ClassCastException, perché newProxyInstance ha creato la classe per implementare tale interfaccia e hai specificato che dovrebbe passare new Class[]{MyServelet.class}.

Affinché il casting non abbia fallito, Java generici deve averlo dedotto T è MyServelet, non MyServeletImplementation. Forse quando hai chiamato instrument, lo faceva così:

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

Quindi il cast doveva MyServelet che dovrebbe avere successo e non farlo MyServeletImplementation, che dovrebbe fallire.

Il motivo per cui dovevi aggiungere @SuppressWarnings("unchecked") È perché il compilatore stava cercando di avvertirti che stavi facendo qualcosa di sbagliato. Aggiungendo la soppressione, hai detto al compilatore che non ti importava perché sapevi cosa stavi facendo. Forse non avresti dovuto aggiungere l'annotazione se non avessi fatto il fatto che avessi ricevuto l'avvertimento in primo luogo?

Suggerimento: il cast generico T proxy = (T) si trasforma in Object proxy = (Object) dal compilatore. ("Digita cancellazione" come menzionato in un'altra risposta).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top