5

Я использую рекурсивное дерево хэшмапов, в частности карту Hashmap, где Object является ссылкой на другой Hashmap и т. Д. Это будет роздано рекурсивным алгоритмом:Java Generics Type Предупреждение о безопасности с рекурсивным Hashmap

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()); 
    } 
} 

Я знаю наверняка Object имеет типа Hashmap<String, Object>, но я раздражен, что я должен подавить предупреждение с помощью @SuppressWarnings("unchecked").

Я буду удовлетворен решением, которое делает либо assert(/*entry.getValue() is of type HashMap<String, Object>*/), либо генерирует исключение, если это не так. Я пошел по маршруту Generics для безопасности типа компиляции, и если я подавил предупреждение, то он победил цель.

Спасибо за ваши комментарии, KSB

ответ

5

Это возможно с помощью общего метода с переменным рекурсивным типом. Попробуйте следующее:

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()); 
    } 
} 

Должен компилироваться без предупреждения.

Однако, если у вас есть контроль над картой и вы можете заменить свой собственный класс, может быть более читаемым сделать класс Node (это похоже на дерево для меня), что содержит a Map вместо этого. Что-то вроде:

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

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

и имеют foo взять Node в качестве второго аргумента вместо этого. Просто предложение.

+0

dear waxwing, Я закончил реализацию второго предложения, потому что выясняется, что мне нужно добавить дополнительные вещи к «узлу», чем просто ссылку на другую хэш-карту. Это также кажется более естественным. Я просто разбираюсь с Java, поэтому не могу понять ваше первое предложение - часть «T extends Map ». Еще раз спасибо, KSB –

5

Вы можете использовать этот класс вместо HashMap:

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

Уважаемый Ха, Не понимаю, почему это может работать (Java noob), поэтому не пробовал. Я пойду с решением узла Waxwing. Спасибо, KSB –

+0

Yeap, создавая класс 'Node' (aka Composite pattern), намного лучше, чем' HashMap'. –

1

Ваша структура данных выглядит так, будто вы хотите представить деревья файлов (имена файлов) вместе с ней. Я бы не рекомендовал делать это с помощью HashMap в качестве типа узла.

Я бы предложил использовать композитный шаблон (см википедию), упрощенный код:

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(); 
    } 
} 

Метод HashMap вы использовали сводится к Комплексу появляясь в DirectoryNode.

+0

Спасибо за мысль. Мои сущности не могут быть разделены на два типа узлов, то есть Directory и Files. Все они - «Файлы». В частности, мне нужно выполнить ту же обработку foo() на всех уровнях иерархии. Я не могу расширить свой код, чтобы выполнить это. –

+0

Почему бы и нет? Вы можете поместить весь код, который вам нужен, в DirectoryNode.foo(). Вы также можете поместить код в узел.foo(), а затем вызовите super.foo() в DirectoryNode.foo(). Тогда Node будет вашим файлом. – Wolfgang

+0

Я вижу, что вы говорите: поместите общий код внутри Node (foo больше не абстрактный) и вызовите команду File and Directory super (filename). Вспомни это. Спасибо, ksb –

Смежные вопросы