- 1
- 2
- 3
public class StringToObjectMap extends HashMap<String, Object> {
public StringToObjectMap(Map<? extends String, ? extends Object> map)
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
+79
public class StringToObjectMap extends HashMap<String, Object> {
public StringToObjectMap(Map<? extends String, ? extends Object> map)
Нет слов выразить мою печаль.
http://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html
Конструктор примет любой мап, у которого ключ это стринг или его потомок, а значение - любой объект. К примеру Map<String, Test>
public StringToObjectMap (Map<String, ?> map)
Ибо ? extends Object==?. Это как писать class A extends Object вместо class A
А вообще желающим постичь женерики в жабе рекомендую читать эпичный труд Анжелики Лагнер.
http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
this?
Standard C++ IOStreams and Locales (ISBN-10: 0321585585)
В скале этот косяк пофиксили, там ковариантность/контравариантность типа определяется на уровне класса, чтобы всем его пользователья не приходилось писать эти экзистенциальные знаки вопроса.
P.S. Все @SuppressWarnings локализованы.
Т.е. я могу писать @SuppressWarnings("НеобработанноеИсключение")?
Чем интерфейс Map<String,Base> отличается от интерфейса Map<String,Derived>? Очевидно, что первый - подмножество второго. То есть в функцию, требующую первый, можно давать второй.
Хотя не, в Map<String,Base> можно засунуть Base, и тогда объект при выходе из метода будет вместо Derived содержать Base, что неправильно. ШАБЛОНОПРОБЛЕМЫ.
Вот был тупо только Map<Object,Object>, не было бы проблемы.
просто в стандартном гете ожидаемый параметр - Object
как следствие, для Map<String, Object> можно сделать get(24) и получить null
2. всегда можно впихнуть дополнительные хелперные методы в класс, для более удобной работы. о них автор тоже умолчал
в целом, в расширении мэпа не вижу ничего плохого
2. В дальнейшем от этого недоразумения наследуются несколько раз, делая видимость гибкой архитектуры, когда вместо одного наследника передается инстанс другого, но все в итоге кастуется к этой говномапе.
Верно. Я тоже так делаю. Только название громоздкое.
Например что-то такое:
SqlMap extends HashMap<String, Object>.
SqlMap - короткое название. Можно еще фабричные методы туда допилить.
SqlMap.make ("a",1, "b",2, "c",3);
К примеру, у меня в проекте есть класс Structs, в котором есть методы Есть класс SafeGet с методами и т.д.
Например
class Params extends HashMap<String, Object>
p = new Params();
...
p.getInt("prop1")
p.getLong("prop2")
…
p.getMinimalAge();
p.getDefaultTimeout();
Мне нравится идея построения дерева абстракций снизу вверх, когда несколько простых абстраций (вроде Map) используются для построения более высокоуровневой абстракции с другим интерфейсом. Каждый следующий уровень использует услуги нижнего, по возможности не раскрывая реализации.
Особенно подозрительно наследование от конкретных, т.е. не абстрактных классов.
Вот и в вашем случае, унаследовав класс Params от HashMap, вы нарушили инкапсуляцию, раскрыв реализацию. Кроме того, вы лишили себя возможности поддержания части инвариантов класса, ведь пользователи имеют возможность вызывать методы HashMap, даже если они не имеют никакого отношения к абстракции параметров (addAll? empty?).
П.С. Если мне потребуется изменить поведение - я определю новый класс, ничего не наследующий и спрячу мэп внутрь.
:P