5

J'utilise une arborescence récursive de hashmaps, en particulier Hashmap map où Object est une référence à une autre Hashmap et ainsi de suite. Ce sera passé autour d'un algorithme récursif:Java Generics Type Avertissement de sécurité avec Hashmap récursif

foo(String filename, Hashmap<String, Object> map) 
{ 
    //some stuff here 
    for (Entry<String, Object> entry : map.entrySet()) 
    { 
     //type warning that must be suppressed 
     foo(entry.getKey(), (HashMap<String, Object>)entry.getValue()); 
    } 
} 

Je sais que Object est de type Hashmap<String, Object> mais je suis irrité que je dois supprimer l'avertissement à l'aide @SuppressWarnings("unchecked").

Je serai satisfait d'une solution qui fait assert(/*entry.getValue() is of type HashMap<String, Object>*/) ou déclenche une exception quand ce n'est pas le cas. Je suis descendu le chemin des génériques pour la sécurité du type de compilation et si je supprime l'avertissement, alors il va à l'encontre du but.

Merci pour vos commentaires, KSB

Répondre

5

Ceci est possible en utilisant une méthode générique avec une variable de type récursif. Essayez ce qui suit:

public <T extends Map<String, T>> void foo(String filename, T map) { 
    //some stuff here 
    for (Map.Entry<String, T> entry : map.entrySet()) { 
     foo(entry.getKey(), entry.getValue()); 
    } 
} 

Doit être compilé sans aucun avertissement. Cependant, si vous avez le contrôle de la carte, et pouvez substituer votre propre classe, il peut être plus lisible de faire un nœud de classe (cela ressemble à un arbre), que contient une carte à la place. Quelque chose comme:

public class Node { 
    private Map<String, Node> children; 

    ... 
    // accessor methods to retrieve children ... 
} 

Et ont foo prendre un Node comme second argument à la place. Juste une suggestion.

+0

cher waxwing, J'ai fini par implémenter votre deuxième suggestion car il s'avère que j'ai besoin d'ajouter des choses supplémentaires au "nœud" plutôt qu'une simple référence à un autre hashmap. Il se sent aussi beaucoup plus naturel. Je commence tout juste à comprendre Java, donc je ne comprends pas votre première suggestion - la partie "T extends Map ". Merci encore une fois, KSB –

5

Vous pouvez utiliser à la place de cette classe HashMap:

public class RecursiveHashMap extends HashMap<String,RecursiveHashMap> 
{ 
} 
+0

Cher Ha, Je ne comprends pas vraiment pourquoi cela pourrait fonctionner (Java noob), par conséquent ne l'ai pas essayé. Je vais avec la solution Node de waxwing. Merci, KSB –

+0

Yeap, la création de la classe 'Node' (aka Composite) est bien meilleure que celle de' HashMap'. –

1

Votre structure de données a l'air de vouloir représenter des arbres de fichiers (noms de fichiers) avec elle. Je ne recommanderais pas de le faire avec HashMap comme type de nœud.

Je vous suggère d'utiliser le motif composite (voir wikipedia), le code simplifié:

abstract class Node 
{ 
    String filename; 
    Node(String filename) { this.filename = filename; } 
    abstract foo(); 
} 

class FileNode implements Node 
{ 
    FileNode(String filename) { super(filename); } 
    foo() { ... } 
} 

class DirectoryNode implements Node 
{ 
    Set<Node> children; 
    DirectoryNode(String filename, Set<Node> children) 
    { 
    super(filename); 
    this.children = children; 
    } 
    foo() 
    { 
    for (Node child : children) child.foo(); 
    } 
} 

Le HashMap que vous utilisez revient à l'ensemble apparaissant dans DirectoryNode.

+0

Merci pour la pensée. Mes entités ne peuvent pas être partitionnées naturellement en deux types de nœud, à savoir Directory et Files. Tous sont des "fichiers". Plus précisément, j'ai besoin de faire le même traitement foo() à tous les niveaux de la hiérarchie. Je ne suis pas en mesure d'étendre votre code pour y parvenir. –

+0

Pourquoi pas? Vous pouvez mettre tout le code dont vous avez besoin dans DirectoryNode.foo(). Vous pouvez également mettre le code dans Node.foo(), puis appelez super.foo() sur DirectoryNode.foo(). Alors Node serait votre fichier. – Wolfgang

+0

Je vois ce que vous dites: Mettez le code commun à l'intérieur de Node (foo n'est plus abstrait) et avez l'appel de fichiers et répertoires super (nom de fichier). Je m'en souviendrai. Merci, ksb –