Pergunta

A pergunta do IMY diz respeito ao comportamento do tipo de elenco com proxy dinâmico e genéricos de Java. Mais especificamente, quero instrumentar um objeto Servelet usando proxy dinâmico. Para uma melhor reutilização, adotei algum modelo de código genérico para criar objetos proxy como abaixo.

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

Aqui é a minha classe de implementação de servet de concreto que implementa a interface MyServelet. No entanto, se eu executar o método acima, ele imprime

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

Então, eu me pergunto o que aconteceu com a declaração de fundição do tipo no snippet de código. Parece que falhou em silêncio, já que o proxy não foi lançado para o MyServeLeTimplementation, mas também não jogou o ClassCastException. Alguém pode me lançar alguma luz sobre isso? Obrigado!

Foi útil?

Solução

Nenhum elenco ocorreu no bytecode compilado real do método, por causa de tipo de apagamento.

Ao gerar bytecode, o compilador trata qualquer variável de um tipo de parâmetro como tendo o mesmo tipo que o limite superior do tipo de parâmetro, ou Object Se o tipo for ilimitado. Então se T no seu método teve a restrição <T extends MyServelet>, o compilador teria tratado proxy Como uma variável de tipo MyServelet, e inseriu um elenco. No entanto, como T é ilimitado, é tratado como uma variável de tipo Object - Assim, nenhum elenco.

Outras dicas

O objetivo do proxy dinâmico é que você não se importa com a classe real do proxy que está sendo devolvido. Você apenas se importa que ele implemente todas as interfaces desejadas e especificadas.

Os javadocs para newProxyInstance Estado:

Retornos:

Uma instância de proxy com o manipulador de invocação especificado de uma classe de proxy que é definida pelo carregador de classe especificado e que implementa as interfaces especificadas

Então, newProxyInstance devolveu uma instância de com.sun.proxy.$Proxy0 (seja o que for, nós realmente não nos importamos), mas também garantiu que seja um MyServelet. Você deve ser capaz de lançá -lo para MyServelet sem a ClassCastException, Porque newProxyInstance criou a classe para implementar essa interface e você especificou que deveria passar new Class[]{MyServelet.class}.

Para que o elenco de tipo não tenha falhado, os genéricos de Java devem ter deduzido que T é MyServelet, não MyServeletImplementation. Talvez quando você ligou instrument, você fez isso assim:

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

Então o elenco era para MyServelet o que deve ter sucesso, e não MyServeletImplementation, que deve falhar.

A razão pela qual você precisava adicionar @SuppressWarnings("unchecked") é porque o compilador estava tentando avisá -lo de que você estava fazendo algo errado. Ao adicionar a supressão, você disse ao compilador que não se importava porque sabia o que estava fazendo. Talvez você não devesse ter adicionado a anotação se não tivesse feito por que estava recebendo o aviso em primeiro lugar?

Dica: o elenco genérico T proxy = (T) é transformado em Object proxy = (Object) pelo compilador. ("Apagação do tipo", conforme mencionado em outra resposta).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top