Почему java.util.Properties реализует Map <Object, Object>, а не Map <String, String> - PullRequest
51 голосов
/ 17 мая 2009

Класс java.util.Properties предназначен для представления карты, ключами и значениями которой являются строки. Это потому, что Properties объекты используются для чтения .properties файлов, которые являются текстовыми файлами.

Итак, почему в Java 5 они модифицировали этот класс для реализации Map<Object,Object>, а не Map<String,String>?

javadoc заявляет:

Поскольку Properties наследуется от Hashtable, методы put и putAll могут применяться к объекту Properties. Их использование настоятельно не рекомендуется, так как они позволяют вызывающей стороне вставлять записи, ключи или значения которых не являются строками. Вместо этого следует использовать метод setProperty. Если метод store или save вызывается для «скомпрометированного» объекта Properties, содержащего не строковый ключ или значение, вызов завершится неудачей.

Поскольку оба ключа и значения должны быть строками, то почему бы не применять их статически, используя правильный универсальный тип?

Я полагаю, что создание Properties реализации Map<String,String> не будет полностью обратно совместимым с кодом, написанным для pre-Java 5. Если у вас есть более старый код, который вставляет нестроки в объект Properties, тогда этот код больше не будет компилироваться Java 5. Но ... разве это не хорошо? Разве весь смысл обобщений заключается в том, чтобы перехватывать такие ошибки типов во время компиляции?

Ответы [ 5 ]

53 голосов
/ 17 мая 2009

Потому что они делали это в спешке в первые дни Java и не понимали, что это может означать через четыре версии.

Обобщения должны были быть частью дизайна Java с самого начала, но эта функция была отброшена как слишком сложная и, в то время, ненужная. В результате большое количество кода в стандартных библиотеках написано в предположении неуниверсальных коллекций. Потребовался прототип языка «Пицца» от Мартина Одерского, чтобы показать, как они могут быть выполнены достаточно хорошо при поддержании почти идеальной обратной совместимости, как с Java-кодом, так и с байт-кодом. Прототип привел к Java 5, в которой классы коллекций были модифицированы с помощью дженериков таким образом, что старый код продолжал работать.

К сожалению, если бы они задним числом заставили Properties наследовать от Map<String, String>, то следующий ранее действительный код перестал бы работать:

Map<Object, Object> x = new Properties()
x.put("flag", true)

Почему кто-то так поступил, мне не под силу, но приверженность Sun обратной совместимости в Java перешла не только героическую, но и бессмысленную.

В настоящее время большинство образованных наблюдателей ценит то, что Properties вообще не должен был унаследовать от Map. Вместо этого он должен обернуться вокруг Map, раскрывая только те функции Map, которые имеют смысл.

Со времени переизобретения Java Мартин Одерский начал создавать новый язык Scala, который стал чище, унаследовал меньше ошибок и открыл новые возможности в ряде областей. Если вы находите раздражение в Java, посмотрите на это.

27 голосов
/ 17 мая 2009

Изначально предполагалось, что Properties действительно будет расширяться Hashtable<String,String>. К сожалению, реализация методов моста создала проблему. Properties, определенный таким образом, заставляет javac генерировать синтетические методы. Properties должен определить, скажем, метод get, который возвращает String, но должен переопределить метод, который возвращает Object. Поэтому добавлен метод синтетического моста.

Предположим, у вас был класс, написанный в старые дурные 1,4 дня. Вы переопределили некоторые методы в Properties. Но то, что вы еще не сделали, это переопределение новых методов. Это приводит к непреднамеренному поведению. Чтобы избежать этих методов моста, Properties расширяет Hashtable<Object,Object>. Точно так же Iterable не возвращает (только для чтения) SimpleIterable, поскольку это добавило бы методы к Collection реализациям.

13 голосов
/ 18 марта 2011

Однострочник (двухслойный без предупреждений) для создания карты из свойств:

@SuppressWarnings({ "unchecked", "rawtypes" })
Map<String, String> sysProps = new HashMap(System.getProperties());
4 голосов
/ 17 мая 2009

Обратная совместимость.

2 голосов
/ 17 мая 2009

Причина: принцип подстановки Лискова и обратная совместимость. Properties расширяет Hashtable и, таким образом, должно принимать все сообщения, которые Hashtable будет принимать - и это означает, что put(Object, Object). И он должен расширять обычный Hashtable вместо Hashtable<String, String>, потому что Generics были реализованы способом, совместимым с нисходящим интерфейсом, через стирание типа , поэтому, как только компилятор сделал свое дело, обобщений не будет.

...