Pergunta

Eu queria saber qual é o tipo de dados da variável de modelo, se o retorno é definido como um modelo. Eu já vi isso em um algum lugar código, mas eu não sei onde é que ele lançou o valor recuperado da sessão.

public class RequestObject {
    public <T> T getFromSessionMap(String sessionKey) {
        return (T)session.getAttribute(sessionKey);
    }
}

O código para esta fora é:

MyClassType type = request.getFromSessionMap("abc");

A linha de encontros ClassCastException quando casting para o meu objeto. Mas quando eu adiciono para assistir session.getAttribute ( "abc"), mostra que o tipo é MyClassType. Qualquer ajuda seria apreciada.

Aparentemente este código especial para a utilização do modelo faz o retorno de getFromSessionMap um tipo de variável e, portanto, não há necessidade de um elenco. Isso funciona em todos os casos, mas de repente ele falhou em uma parte do código.

Foi útil?

Solução

Aparentemente este código especial para a utilização de template faz o retorno de getFromSessionMap um tipo variável e portanto, não há necessidade de um elenco.

Fundamentalmente, há tem de ser a algum lugar typecast entre a obtenção do resultado de session.getAttribute(sessionKey) ea atribuição de MyClassType. A linguagem Java (ea JVM) não permitirá algum objeto que não é uma instância MyClassType (ou um subtipo do mesmo) a ser atribuído a uma variável MyClassType.

Não importa como você escrever o código, a typecast tem que ocorrer . E uma vez que o atributo (aparentemente) não é um MyClassType (ou subtipo), você está recebendo um ClassCastException.

Assim, a verdadeira questão é porque você não está recebendo um erro de compilação? E a resposta é a @SuppressWarnings("unchecked")! Se você removeu esse aviso, você iria receber uma mensagem de erro "conversão de tipo inseguro" para esta linha:

return (T) session.getAttribute(sessionKey);

Na verdade, Java não pode fazer uma (real) Tipo de elenco para um tipo genérico. E é isso que a mensagem de aviso / erro está lá para apontar. Na verdade, uma vez que o código foi compilado, este código

public <T> T getFromSessionMap(String sessionKey) {
    return (T)session.getAttribute(sessionKey);
}

é realmente diferente no significado deste:

public Object getFromSessionMap(String sessionKey) {
    return session.getAttribute(sessionKey);
}

Tecnicamente falando, isso é chamado de "tipo de apagamento".

Então, onde é a verificação de tipo / typecast realmente ocorrendo? A resposta é nesta linha:

MyClassType type = request.getFromSessionMap("abc");

Mesmo que você não tenha escrito um typecast aqui, o código gerado pelo compilador Java faz um typecast antes de atribuir o valor para type. Tem que ser. Porque até onde ele sabe, a instância é atribuição poderia ser qualquer tipo de objeto.

Outros cartazes têm sugerido a adição de um argumento de classe para getFromSessionMap. Por si só isto faz absolutamente nada . Se você também substituir o corpo do método com:

return clazz.cast(session.getAttribute(sessionKey));

você vai fazer com que o método de realmente fazer uma verificação de tipo real. Mas isso só causa ClassCastException para ser jogado em um lugar diferente. E a declaração de atribuição irá ainda fazer um tipo elenco escondido !!

Outras dicas

No exemplo da questão, o tipo de retorno é T. O tipo apagado será Object como, implicitamente, T extends Object. O elenco real é executada no bytecode do método chamando (você pode usar javap -c para ver isso).

Geralmente, você deve manter o número de objetos "de alto nível" em sessões tão pequeno quanto possível. Um dos benefícios de fazer isso, é já não existe a necessidade de métodos hacky como estes.

Qualquer ajuda seria apreciada porque o meu código encontra ClassCastException.

Se você está recebendo um ClassCastException, isso significa que você está tentando lançar algo em algo que não é, como no código a seguir:

Map session = new HashMap();
session.put("date", "2009-11-12");
Date today = (Date) session.get("date"); // tries to convert String to Date

O ClassCastException deve ter uma mensagem de detalhe esclarecedor, como "java.lang.String não pode ser convertido para java.util.Date".

Você usar o tipo fundido dentro do corpo do método ( '(T) session.getAttribute (sessionKey)' ).

Isso significa que você diz explicitamente ao compilador 'Eu estou absolutamente certo de que objeto retornado IS-A T e pronto para erro punho se não for' .

Aqui a sua suposição sobre tipo de atributo estava incorreto e você tem um erro. Então, tudo está correto e runtime já fornece-lhe com o tipo de objeto de atributo real que não é IS-A MyClassType.

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