Java Generics Wable Safety Safety Safety с рекурсивным хэшмапом
-
20-09-2019 - |
Вопрос
Я использую рекурсивное дерево Hashmaps, в частности, карта Hashmap, где объект является ссылкой на другой 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
Решение
Это возможно с использованием общего метода с переменной рекурсивного типа. Попробуйте следующее:
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());
}
}
Следует собирать нормально без каких -либо предупреждений.
Однако, если у вас есть контроль над картой и вы можете заменить свой собственный класс, это может быть более читабельным, чтобы создать узел класса (это похоже на дерево), что содержит карта вместо этого. Что-то типа:
public class Node {
private Map<String, Node> children;
...
// accessor methods to retrieve children ...
}
И имеют foo
принять Node
как его второй аргумент вместо этого. Просто предложение.
Другие советы
Вы можете использовать этот класс вместо хэшмапа:
public class RecursiveHashMap extends HashMap<String,RecursiveHashMap>
{
}
Ваша структура данных выглядит так, как будто вы хотите представлять деревья файлов (имена файлов). Я бы не рекомендовал делать это с 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.