Pergunta

No meu arquivo de contexto de aplicativo da primavera, tenho algo como:

<util:map id="someMap" map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.String">
    <entry key="some_key" value="some value" />
    <entry key="some_key_2" value="some value" />   
</util:map>

Na classe Java, a implementação se parece:

private Map<String, String> someMap = new HashMap<String, String>();
someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");

No Eclipse, vejo um aviso que diz:

Tipo Segurança: sem verificação fundido de objeto para hashmap

O que eu fiz errado? Como resolvo o problema?

Foi útil?

Solução

Bem, antes de tudo, você está desperdiçando memória com o novo HashMap chamada de criação. Sua segunda linha desconsidera completamente a referência a este hashmap criado, disponibilizando -a para o coletor de lixo. Então, não faça isso, use:

private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");

Em segundo lugar, o compilador está reclamando que você lança o objeto para um HashMap sem verificar se for um HashMap. Mas, mesmo se você fizesse:

if(getApplicationContext().getBean("someMap") instanceof HashMap) {
    private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");
}

Você provavelmente ainda receberia esse aviso. O problema é, getBean retorna Object, então não se sabe qual é o tipo. Convertendo em HashMap Diretamente não causaria o problema com o segundo caso (e talvez não haja um aviso no primeiro caso, não tenho certeza de quão pedante o compilador Java é com avisos para o Java 5). No entanto, você está convertendo para um HashMap<String, String>.

Hashmaps são realmente mapas que tomam um objeto como chave e têm um objeto como um valor, HashMap<Object, Object> Se você for. Portanto, não há garantia de que, quando você obtém seu feijão, ele pode ser representado como um HashMap<String, String> Porque você poderia ter HashMap<Date, Calendar> Porque a representação não genérica retornada pode ter objetos.

Se o código compilar e você pode executar String value = map.get("thisString"); Sem erros, não se preocupe com esse aviso. Mas se o mapa não for completamente de teclas de string para valores de string, você receberá um ClassCastException Em tempo de execução, porque os genéricos não podem impedir que isso aconteça neste caso.

Outras dicas

O problema é que um elenco é uma verificação de tempo de execução - mas devido ao apagamento do tipo, em tempo de execução, na verdade, não há diferença entre um HashMap<String,String> e HashMap<Foo,Bar> para qualquer outro Foo e Bar.

Usar @SuppressWarnings("unchecked") e segure seu nariz. Ah, e campanha para genéricos reificados em java :)

Como as mensagens acima indicam, a lista não pode ser diferenciada entre um List<Object> e a List<String> ou List<Integer>.

Eu resolvi esta mensagem de erro para um problema semelhante:

List<String> strList = (List<String>) someFunction();
String s = strList.get(0);

com o seguinte:

List<?> strList = (List<?>) someFunction();
String s = (String) strList.get(0);

Explicação: O primeiro tipo de conversão verifica se o objeto é uma lista sem se preocupar com os tipos mantidos dentro (pois não podemos verificar os tipos internos no nível da lista). A segunda conversão agora é necessária porque o compilador sabe apenas que a lista contém algum tipo de objetos. Isso verifica o tipo de cada objeto na lista como é acessado.

Um aviso é exatamente isso. Um aviso. Às vezes, os avisos são irrelevantes, às vezes não são. Eles costumam chamar sua atenção para algo que o compilador acha que poderia ser um problema, mas pode não ser.

No caso de elencos, sempre dará um aviso neste caso. Se você estiver absolutamente certo de que um determinado elenco estará seguro, considere adicionar uma anotação como essa (não tenho certeza da sintaxe) pouco antes da linha:

@SuppressWarnings (value="unchecked")

Você está recebendo esta mensagem porque o getBean retorna uma referência de objeto e você a está lançando para o tipo correto. O Java 1.5 lhe dá um aviso. Essa é a natureza de usar o Java 1.5 ou melhor com código que funciona como este. A primavera tem a versão TypeAfe

someMap=getApplicationContext().getBean<HashMap<String, String>>("someMap");

na sua lista de tarefas.

Se você realmente deseja se livrar dos avisos, uma coisa que você pode fazer é criar uma classe que se estende a partir da classe genérica.

Por exemplo, se você está tentando usar

private Map<String, String> someMap = new HashMap<String, String>();

Você pode criar uma nova classe como tal

public class StringMap extends HashMap<String, String>()
{
    // Override constructors
}

Então quando você usa

someMap = (StringMap) getApplicationContext().getBean("someMap");

O compilador sabe quais são os tipos (não mais genéricos) e não haverá aviso. Essa nem sempre pode ser a solução perfeita, alguns podem argumentar que esse tipo de derrota o objetivo das classes genéricas, mas você ainda está reutilizando o mesmo código da classe genérica, você está apenas declarando em horário de compilação que tipo você quer usar.

Outra solução, se você se for lançando muito o mesmo objeto e não quiser espalhar seu código com @SupressWarnings("unchecked"), seria criar um método com a anotação. Dessa forma, você está centralizando o elenco e, com sorte, reduzindo a possibilidade de erro.

@SuppressWarnings("unchecked")
public static List<String> getFooStrings(Map<String, List<String>> ctx) {
    return (List<String>) ctx.get("foos");
}

Abaixo o código causa o tipo de aviso de segurança

Map<String, Object> myInput = (Map<String, Object>) myRequest.get();

Gambiarra

Crie um novo objeto de mapa sem mencionar os parâmetros porque o tipo de objeto mantido dentro da lista não é verificado.

Passo 1: Crie um novo mapa temporário

Map<?, ?> tempMap = (Map<?, ?>) myRequest.get();

Passo 2: Instanciar o mapa principal

Map<String, Object> myInput=new HashMap<>(myInputObj.size());

Etapa 3: Itera o mapa temporário e defina os valores no mapa principal

 for(Map.Entry<?, ?> entry :myInputObj.entrySet()){
        myInput.put((String)entry.getKey(),entry.getValue()); 
    }

A solução para evitar o aviso desmarcado:

class MyMap extends HashMap<String, String> {};
someMap = (MyMap)getApplicationContext().getBean("someMap");
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top