2008-11-04 5 views
185

Dans mon fichier contexte d'application de printemps, j'ai quelque chose comme:sécurité Type: décoché jeté

<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 classe java, la mise en œuvre ressemble à:

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

Dans Eclipse, je vois un avertissement qui dit:

sécurité type: non contrôlé de l'objet moulé à hashmap

Qu'est-ce que j'ai fait de mal? Comment puis-je résoudre le problème?

+0

connexes/duper: [Comment puis-je adresser des avertissements de la distribution non vérifiées?] (Http://stackoverflow.com/q/509076) – blahdiblah

+0

double possible de [Comment traiter les avertissements de cast non vérifiés?] (http://stackoverflow.com/questions/509076/how-do-i-address-unchecked-cast-warnings) –

+0

Je suis venu avec une routine pour vérifier réellement la distribution à HashMap paramétré, ce qui élimine l'avertissement de cast décochée: [link] (http://stackoverflow.com/questions/509076/how-do-i-address-unchecked-cast-warnings/509230#509230) Je dirais que est la solution "correcte", mais si elle vaut la peine d'être discutable. :) – skiphoppy

Répondre

211

Eh bien, tout d'abord, vous gaspillez de la mémoire avec le nouvel appel de création HashMap. Votre deuxième ligne ignore complètement la référence à cette hashmap créée, la rendant alors disponible au garbage collector. Alors, ne faites pas cela, utilisez:

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

En second lieu, le compilateur se plaint que vous lancez l'objet à un HashMap sans vérifier si elle est un HashMap. Mais, même si vous deviez faire:

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

Vous obtiendrez probablement toujours cet avertissement. Le problème est, getBean renvoie Object, donc on ne sait pas quel est le type. Le convertir en HashMap directement ne causerait pas le problème avec le second cas (et peut-être qu'il n'y aurait pas d'avertissement dans le premier cas, je ne suis pas sûr de la pédantité du compilateur Java avec les avertissements pour Java 5). Cependant, vous le convertissez en HashMap<String, String>. Les HashMaps sont en réalité des cartes qui prennent un objet comme une clé et ont un objet comme valeur, HashMap<Object, Object> si vous voulez. Ainsi, il n'y a aucune garantie que lorsque vous obtenez votre bean, il peut être représenté comme HashMap<String, String> parce que vous pourriez avoir HashMap<Date, Calendar> parce que la représentation non générique qui est retournée peut avoir des objets.

Si le code compile et que vous pouvez exécuter String value = map.get("thisString"); sans aucune erreur, ne vous inquiétez pas de cet avertissement. Mais si la carte n'est pas complètement de chaînes de caractères à des valeurs de chaîne, vous obtiendrez un ClassCastException lors de l'exécution, car les génériques ne peuvent pas bloquer cela dans ce cas.

+10

C'était il ya quelque temps, mais je cherchais une réponse sur le type de vérification d'un ensemble avant une distribution, et vous ne pouvez pas instanceof sur un générique paramétré. par exemple. if (event.getTarget instanceof Set ) Vous pouvez uniquement taper un générique avec un? et cela ne supprimera pas l'avertissement de cast. par exemple. if (event.getTarget instanceof Set ) – garlicman

21

Un avertissement est juste cela. Un avertissement. Parfois, les avertissements ne sont pas pertinents, parfois ils ne le sont pas. Ils sont utilisés pour attirer votre attention sur quelque chose que le compilateur pense être un problème, mais peut-être pas.

Dans le cas des moulages, il y aura toujours un avertissement dans ce cas. Si vous êtes absolument certain qu'un casting particulier sera en sécurité, alors vous devriez envisager d'ajouter une annotation comme celui-ci (je ne suis pas sûr de la syntaxe) juste avant la ligne:

@SuppressWarnings (value="unchecked") 
+8

-1: un avertissement ne doit jamais être accepté. Ou supprimer ce type d'avertissement ou le réparer. Il viendra le moment où vous aurez de nombreux avertissements et vous ne verrez pas le pertinent une fois. – ezdazuzena

+5

Vous ne pouvez pas vraiment éviter les avertissements de lancement de classe lorsque vous lancez des génériques paramétrés dans i.e Map, c'est donc la meilleure réponse à la question d'origine. – muttonUp

9

Vous obtenez ce message parce que getBean renvoie une référence d'objet et vous le transtypez dans le bon type. Java 1.5 vous donne un avertissement. C'est la nature d'utiliser Java 1.5 ou mieux avec du code qui fonctionne comme ça. Le ressort a la version de typesafe

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

sur sa liste de tâches.

248

Le problème est qu'un casting est un contrôle d'exécution - mais en raison de l'effacement de type, lors de l'exécution il n'y a en fait pas de différence entre un HashMap<String,String> et HashMap<Foo,Bar> pour toute autre Foo et Bar.

Utilisez @SuppressWarnings("unchecked") et tenez votre nez. Oh, la liste et la campagne pour les génériques réifiés en Java :)

+12

Je vais prendre les génériques réifiés de Java sur NSMutableWhatever non typé, ce qui ressemble à un saut en arrière de dix ans, n'importe quel jour de la semaine. Au moins, Java essaie. –

+11

Exactement. Si vous insistez sur le contrôle de type, il ne peut être fait avec HashMap et cela ne supprimera pas l'avertissement car c'est la même chose que de ne pas vérifier les types génériques. Ce n'est pas la fin du monde, mais ennuyeux que vous soyez surpris en train de supprimer un avertissement ou de vivre avec. – garlicman

+1

@JonSkeet Qu'est-ce qu'un générique réifié? – SasQ

53

Comme les messages ci-dessus indiquent ne peut être différenciée entre un List<Object> et un List<String> ou List<Integer>.

Je l'ai résolu ce message d'erreur pour un problème similaire:

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

ce qui suit:

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

Explication: La première conversion de type vérifie que l'objet est une liste sans se soucier de les types détenus à l'intérieur (puisque nous ne pouvons pas vérifier les types internes au niveau de la liste). La deuxième conversion est maintenant requise car le compilateur sait seulement que la liste contient des sortes d'objets. Cela vérifie le type de chaque objet dans la liste lors de son accès.

+1

vous avez raison mon ami. Au lieu de lancer la liste, il suffit de l'itérer et de lancer chaque élément, l'avertissement n'apparaîtra pas, génial. –

+0

Cela a supprimé l'avertissement, mais je ne suis toujours pas confiant: P – mumair

4

Si vous voulez vraiment vous débarrasser des avertissements, une chose que vous pouvez faire est de créer une classe qui s'étend de la classe générique.

Par exemple, si vous essayez d'utiliser

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

Vous pouvez créer une nouvelle classe comme telle

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

Ensuite, lorsque vous utilisez

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

Le compilateur T-ELLE savoir quels sont les types (non plus génériques), et il n'y aura pas d'avertissement. Cela peut ne pas toujours être la solution parfaite, certains pourraient argumenter que ce genre de défait le but des classes génériques, mais vous réutilisez toujours le même code de la classe générique, vous déclarez simplement au moment de la compilation quel type vous voulez utiliser.

1

Une autre solution, si vous trouvez souvent le même objet et que vous ne voulez pas vider votre code avec @SupressWarnings("unchecked"), serait de créer une méthode avec l'annotation. De cette façon, vous centralisez la distribution et, espérons-le, réduisez la possibilité d'erreur.

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

Ci-dessous le code provoque la sécurité Avertissement de type

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

Solution

Créer une nouvelle carte objet sans mentionner les paramètres parce que le type d'objet tenu dans la liste est n ot vérifié.

Étape 1: Créer une nouvelle carte temporaire

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

Étape 2: Instantiate la carte principale

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

Étape 3: Itérer la carte temporaire et définir les valeurs dans la carte principale

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