Проблема с этим кодом состоит в том, что система типов не позволяет вам помещать объект в Map
с типом ключа ?
.Это потому, что если тип ключа ?
, компилятор не знает, что на самом деле хранится на карте - это может быть Object
, или Integer
, или List<Object>
- и поэтому он не может подтвердить, чтото, что вы пытаетесь добавить на карту, на самом деле имеет правильный тип и не будет неуместным в Map
.Например, если у вас есть этот метод:
public static void breakMyMap(Map<?, ?> m) {
m.put(new Object(), new Object()); // Won't compile
}
, а затем напишите код, подобный следующему:
Map<String, String> myMap = new HashMap<String, String>();
breakMyMap(myMap);
Тогда, если код в breakMyMap
будет скомпилирован, он поместитпара Object
s в качестве ключей и значений в Map<String, String>
, нарушая инвариант, что все элементы действительно String
s.
Чтобы исправить это, вместо того, чтобы заставить эту функцию работать на Map<?, ?>
, измените функцию, чтобы у вас было больше информации о типе ключей и значений.Например, вы можете попробовать это:
public static <K, V> Map<K, V> filterAttrs(Map<K, V> args, String... unless) {
Map<K, V> filteredAttrs = new HashMap<K, V>();
Arrays.sort(unless);
for (K o : args.keySet()) {
String attr = o.toString();
if (Arrays.binarySearch(unless, o.toString()) < 0 ) {
filteredAttrs.put(o, args.get(o));
}
}
return filteredAttrs;
}
Теперь, когда компилятор знает, что тип ключа K
, он может проверить, что put
не будет смешивать типы ключей вmap.
Еще одна вещь, на которую я должен обратить внимание, это то, что ваш код никогда бы не работал, даже если бы он компилировался.Причина в том, что строка
Map<?, ?> filteredAttrs = Map.class.newInstance();
вызовет исключение во время выполнения, потому что Map
является интерфейсом , а не классом, и поэтому пытается использовать newInstance
для созданияэкземпляр этого не будет работать правильно.Чтобы это исправить, вы можете либо явно указать тип карты (как я делал в приведенном выше коде), либо получить класс аргумента:
Map<K, V> filteredAttrs = args.getClass().newInstance();
Конечно, это не такгарантированно будет работать, хотя общий контракт для коллекций состоит в том, что все коллекции должны иметь конструктор без аргументов.
Надеюсь, это поможет!