Digitare sicurezza: cast non selezionato

Nel mio file di contesto dell’applicazione spring, ho qualcosa del tipo:

    

Nella class java, l’implementazione è simile a:

 private Map someMap = new HashMap(); someMap = (HashMap)getApplicationContext().getBean("someMap"); 

In Eclipse, vedo un avviso che dice:

Digitare sicurezza: cast non selezionato da Object a HashMap

Che cosa ho fatto di sbagliato? Come risolvo il problema?

    Bene, prima di tutto, stai sprecando memoria con la nuova chiamata alla creazione di HashMap . La seconda riga ignora completamente il riferimento a questa hashmap creata, rendendola disponibile al garbage collector. Quindi, non farlo, usa:

     private Map someMap = (HashMap)getApplicationContext().getBean("someMap"); 

    In secondo luogo, il compilatore si lamenta di aver lanciato l’object su una HashMap senza verificare se si tratta di una HashMap . Ma, anche se tu dovessi fare:

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

    Probabilmente otterresti comunque questo avvertimento. Il problema è che getBean restituisce Object , quindi non si sa quale sia il tipo. Convertirlo direttamente in HashMap non causerebbe il problema con il secondo caso (e forse non ci sarebbe un avvertimento nel primo caso, non sono sicuro di quanto pedante sia il compilatore Java con gli avvisi per Java 5). Tuttavia, lo stai convertendo in HashMap .

    HashMaps sono in realtà mappe che prendono un object come chiave e hanno un object come valore, HashMap se lo desideri. Pertanto, non vi è alcuna garanzia che quando si ottiene il bean sia ansible rappresentarlo come HashMap perché si potrebbe avere HashMap perché la rappresentazione non generica restituita può contenere qualsiasi object.

    Se il codice viene compilato ed è ansible eseguire String value = map.get("thisString"); senza errori, non preoccuparti di questo avviso. Ma se la mappa non è completamente di chiavi stringa per i valori stringa, si otterrà un ClassCastException in fase di esecuzione, in quanto i generici non possono impedire che ciò accada in questo caso.

    Il problema è che un cast è un controllo di runtime, ma a causa della cancellazione del tipo, in fase di esecuzione non c’è alcuna differenza tra HashMap e HashMap per qualsiasi altro Foo e Bar .

    Usa @SuppressWarnings("unchecked") e tieni il naso. Oh, e campagna per generici reificati in Java 🙂

    Come indicano i messaggi precedenti, l’Elenco non può essere differenziato tra un List e un List o List .

    Ho risolto questo messaggio di errore per un problema simile:

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

    con il seguente:

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

    Spiegazione: La prima conversione del tipo verifica che l’object sia una lista senza preoccuparsi dei tipi mantenuti all’interno (poiché non è ansible verificare i tipi interni a livello di elenco). La seconda conversione è ora necessaria perché il compilatore sa solo che l’Elenco contiene una sorta di oggetti. Ciò verifica il tipo di ciascun object nell’Elenco al momento dell’accesso.

    Un avvertimento è proprio questo. Un avvertimento. A volte gli avvertimenti sono irrilevanti, a volte non lo sono. Sono abituati a richiamare la tua attenzione su qualcosa che il compilatore pensa possa essere un problema, ma potrebbe non esserlo.

    Nel caso di cast, in questo caso darà sempre un avvertimento. Se sei assolutamente certo che un cast particolare sarà sicuro, dovresti prendere in considerazione l’aggiunta di un’annotazione come questa (non sono sicuro della syntax) subito prima della linea:

     @SuppressWarnings (value="unchecked") 

    Stai ricevendo questo messaggio perché getBean restituisce un riferimento all’object e lo stai trasmettendo al tipo corretto. Java 1.5 ti dà un avvertimento. Questa è la natura dell’utilizzo di Java 1.5 o superiore con codice che funziona in questo modo. Spring ha la versione typesafe

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

    sulla sua lista di cose da fare.

    Se vuoi davvero liberarti degli avvertimenti, una cosa che puoi fare è creare una class che si estenda dalla class generica.

    Ad esempio, se stai cercando di usarlo

     private Map someMap = new HashMap(); 

    Puoi creare una nuova class come tale

     public class StringMap extends HashMap() { // Override constructors } 

    Quindi quando usi

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

    Il compilatore sa quali sono i tipi (non più generici) e non ci saranno avvisi. Questa potrebbe non essere sempre la soluzione perfetta, alcuni potrebbero sostenere questo tipo di sconfitte allo scopo delle classi generiche, ma stai ancora riutilizzando tutto lo stesso codice dalla class generica, stai solo dichiarando in fase di compilazione quale tipo tu vuoi usare.

    Un’altra soluzione, se ti ritrovi a lanciare lo stesso object e non vuoi @SupressWarnings("unchecked") tuo codice con @SupressWarnings("unchecked") , sarebbe quello di creare un metodo con l’annotazione. In questo modo stai centralizzando il cast e, si spera, riducendo la possibilità di errore.

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

    Di seguito il codice causa Tipo di sicurezza Avvertenza

    Map myInput = (Map) myRequest.get();

    Soluzione

    Creare un nuovo object mappa senza menzionare i parametri poiché il tipo di object contenuto nell’elenco non è verificato.

    Passaggio 1: crea una nuova mappa temporanea

    Map tempMap = (Map) myRequest.get();

    Passaggio 2: Istanziare la mappa principale

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

    Passaggio 3: Iterate la mappa temporanea e impostate i valori nella mappa principale

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

    La soluzione per evitare l’avviso non controllato:

     class MyMap extends HashMap {}; someMap = (MyMap)getApplicationContext().getBean("someMap");