2008-11-04 13 views
185

En mi archivo de contexto de aplicación de primavera, tengo algo como:seguridad Tipo: Desactivada fundido

<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> 

En la clase de Java, la puesta en práctica se parece a:

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

En Eclipse, veo una advertencia que dice:

seguridad Tipo: Desactivada fundido del objeto a Hashmap

¿Qué hice mal? ¿Cómo resuelvo el problema?

+0

Relacionado/víctima: [¿Cómo enviar advertencias elenco sin marcar?] (Http://stackoverflow.com/q/509076) – blahdiblah

+0

posible duplicado de [¿Cómo abordo las advertencias de casteo no revisadas?] (http://stackoverflow.com/questions/509076/how-do-i-address-unchecked-cast-warnings) –

+0

Se me ocurrió una rutina para verificar el reparto al HashMap parametrizado, que elimina la advertencia de lanzamiento sin marcar: [link] (http://stackoverflow.com/questions/509076/how-do-i-address-unchecked-cast-warnings/509230#509230) Diría esto es la solución "correcta", pero si vale la pena puede ser discutible. :) – skiphoppy

Respuesta

211

Bueno, antes que nada, está desperdiciando memoria con la nueva llamada de creación HashMap. Su segunda línea ignora por completo la referencia a este hashmap creado, por lo que está disponible para el recolector de elementos no utilizados. Por lo tanto, no haga eso, su uso:

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

En segundo lugar, el compilador se queja de que lanzas el objeto a una HashMap sin comprobar si es un HashMap. Pero, incluso si tuviera que hacer:

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

Probablemente recibirá esta advertencia. El problema es que getBean devuelve Object, por lo que se desconoce de qué tipo es. Convertirlo a HashMap directamente no causaría el problema con el segundo caso (y tal vez no habría una advertencia en el primer caso, no estoy seguro de cuán pedante es el compilador de Java con advertencias para Java 5). Sin embargo, lo está convirtiendo a HashMap<String, String>.

Los HashMaps son realmente mapas que toman un objeto como clave y tienen un objeto como valor, HashMap<Object, Object> si se quiere. Por lo tanto, no hay garantía de que cuando obtenga su bean pueda representarse como HashMap<String, String> porque podría tener HashMap<Date, Calendar> porque la representación no genérica que se devuelve puede tener cualquier objeto.

Si el código se compila y puede ejecutar String value = map.get("thisString"); sin ningún error, no se preocupe por esta advertencia. Pero si el mapa no es completamente de claves de cadena para valores de cadena, obtendrá un ClassCastException en tiempo de ejecución, porque los genéricos no pueden bloquear esto en este caso.

+10

Esto fue hace un tiempo, pero estaba buscando una respuesta en el tipo de comprobación de un conjunto antes de un molde, y no puede instanceof en un genérico parametrizado. p.ej. if (event.getTarget instanceof Set ) Solo puede escribir check a generic con? y eso no eliminará la advertencia de lanzamiento. p.ej. if (event.getTarget instanceof Set ) – garlicman

21

Una advertencia es solo eso. Una advertencia. A veces, las advertencias son irrelevantes, a veces no lo son. Están acostumbrados a llamar su atención sobre algo que el compilador cree que podría ser un problema, pero puede no serlo.

En el caso de los moldes, siempre dará una advertencia en este caso. Si está absolutamente seguro de que un reparto particular será seguro, entonces usted debería considerar la adición de una anotación como esto (no estoy seguro de la sintaxis) justo antes de la línea:

@SuppressWarnings (value="unchecked") 
+8

-1: nunca se debe aceptar una advertencia. O suprima este tipo de advertencias o corrígelo. Llegará el momento en el que tendrás que recibir muchas advertencias y no verás la relevante una vez. – ezdazuzena

+5

Realmente no se puede evitar las advertencias de lanzamiento de clase cuando se lanzan genéricos parametrizados, es decir, Mapa, por lo que esta es la mejor respuesta para la pregunta original. – muttonUp

9

Usted está recibiendo este mensaje porque getBean devuelve una referencia a Objeto y la está transfiriendo al tipo correcto. Java 1.5 te da una advertencia. Esa es la naturaleza de usar Java 1.5 o superior con un código que funciona así. Spring tiene la versión tipo seguro

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

en su lista de tareas pendientes.

248

El problema es que un molde es un cheque en tiempo de ejecución - pero debido al tipo de borrado, en tiempo de ejecución no hay realmente ninguna diferencia entre un HashMap<String,String> y HashMap<Foo,Bar> para cualquier otro Foo y Bar.

Use @SuppressWarnings("unchecked") y mantenga su nariz. Ah, y la campaña de los genéricos en Java reificadas :)

+12

Tomaré genéricos reificados de Java sobre NSMutableWhatever sin tipo, que se siente como un salto de diez años hacia atrás, cualquier día de la semana. Al menos Java lo está intentando. –

+11

Exactamente. Si insistes en la verificación de tipos, solo se puede hacer con HashMap y eso no eliminará la advertencia ya que es lo mismo que no escribir y verificar los tipos genéricos. No es el fin del mundo, pero es molesto que te pillen suprimiendo una advertencia o viviendo con ella. – garlicman

+1

@JonSkeet ¿Qué es un genérico reificado? – SasQ

53

Como los mensajes anteriormente indican, la lista puede no ser diferenciado entre un List<Object> y una List<String> o List<Integer>.

He resuelto este mensaje de error para un problema similar:

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

con lo siguiente:

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

Explicación: La primera conversión de tipo verifica que el objeto es una lista sin preocuparse los tipos contenidos dentro (ya que no podemos verificar los tipos internos en el nivel de la Lista). La segunda conversión ahora es necesaria porque el compilador solo sabe que la Lista contiene algún tipo de objeto. Esto verifica el tipo de cada objeto en la Lista a medida que se accede.

+1

tienes razón, amigo mío. En lugar de lanzar la lista, simplemente itere y eche cada elemento, la advertencia no aparecerá, impresionante. –

+0

Esto eliminó la advertencia, pero aún no estoy seguro: P – mumair

4

Si realmente desea deshacerse de las advertencias, una cosa que puede hacer es crear una clase que se extienda desde la clase genérica.

Por ejemplo, si usted está tratando de utilizar

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

Puede crear una nueva clase como tales

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

A continuación, cuando se utiliza

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

el compilador saber cuáles son los tipos (ya no genéricos) y no habrá advertencia. Puede que esta no siempre sea la solución perfecta, algunos podrían argumentar que este tipo de método no funciona con las clases genéricas, pero todavía estás reutilizando todo el mismo código de la clase genérica, solo estás declarando en tiempo de compilación de qué tipo quieres usar

1

Otra solución, si se encuentra lanzando el mismo objeto mucho y no quiere ensuciar su código con @SupressWarnings("unchecked"), sería crear un método con la anotación. De esta forma, estás centralizando el elenco y, con suerte, reduciendo la posibilidad de error.

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

A continuación código provoca advertencia de seguridad Tipo

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

Solución

Crear un nuevo objeto de mapa sin mencionar los parámetros debido a que el tipo de objeto a cabo dentro de la lista es n ot verificado

Paso 1: crear un nuevo mapa temporal

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

Paso 2: una instancia del principal Mapa

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

Paso 3: Iterar el Mapa temporal y establece los valores en el mapa principal

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