Ввод объектов в java.util.Properties

Я пытаюсь понять, почему java.util.Properties был реализован таким образом. Он имеет два интерфейса: getProperty/setProperty, который принимает только строки, а put/get принимает любой объект в качестве значения. Эти два интерфейса кажутся перекрывающимися, поэтому строка, добавленная с помощью put(), может быть получена с помощью getProperty().

Кажется, что есть некоторые проблемы с этим странным гибридным интерфейсом. Помещение объекта, который переопределяет свойство строки, имеет побочный эффект очистки строкового значения, создавая нуль как результат getProperty. Добавление целого числа или какого-либо другого значения, которое имеет простой перевод строк, может быть неправильно истолковано как значение реального свойства (но как свойство оно всегда равно нулю).

Мой вопрос: есть ли для этого реальная, практическая причина? Как я подозреваю, это полупродуманная реализация?

Ответ 1

Джошуа Блох упоминает это явно в Эффективная Java

[из главы 4] В случае Properties дизайнеры предполагали, что в качестве ключей и значений допускаются только строки, но прямой доступ к базовому Hashtable позволяет этому инварианту нарушаться. Как только этот инвариант нарушен, уже невозможно использовать другие части API свойств (load и store). К тому времени, когда эта проблема была обнаружена, было слишком поздно исправлять ее, потому что клиенты зависели от использования ключей и значений nonstring.

Этот текст используется в контексте использования композиции над наследованием. Он в основном использует это как пример того, когда композицию следует использовать вместо наследования. Если Properties обернул a Map вместо того, чтобы расширять один, он мог бы принудительно использовать инвариантное использование String в качестве ключей и значений.

Итак, ответ: это был надзор.

Ответ 2

Доступ к put и get является результатом Properties, являющегося расширением Hashtable, и два метода не должны использоваться (но не могут быть скрыты от реализации из-за их общедоступного доступа в суперклассе).

В Javadocs есть хорошая заметка о том, почему вы не должны использовать эти методы, и вместо этого должны использовать только строки:

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

Как отмечает @yshavit, для Properties было бы более целесообразно расширить Hashtable<String, String>, чем хэш-таблицу из двух объектов, но это, скорее всего, было принято решение поддерживать обратную совместимость, поскольку любые программы, использующие get/put с любыми объектами, отличными от String, были бы нарушены таким изменением.

Ответ 3

Официальная документация гласит

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

http://docs.oracle.com/javase/8/docs/api/java/util/Properties.html

Ответ 4

Из Java Docs

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

Ответ 5

Properties extends Hashtable, поэтому вы можете использовать Properties в любом месте, где вы можете использовать Hashtable.

Класс Hashtable содержит функции get() и put().

Ответ 6

put(key, value) и get(key) являются остатками сомнительного решения о продолжении Properties Hashtable в тот же день. Такое поведение не может быть изменено, так как оно нарушит совместимость в обратном направлении, но любая половина руководства по достойному стилю, включая собственно документацию API, рекомендует никогда не использовать эти методы.

Ответ 7

Как говорили другие, вы должны использовать его только для Strings. Существуют способы сериализации объекта как строки и получения его, но, очевидно, это не для этого. Я понимаю, что это очень раздражает, так как он ближе всего подходит для кросс-платформенного способа сохранения и извлечения данных приложения. Насколько я знаю, нет официального способа сохранить вещи, отличные от строк в папке, скрытой от пользователя, несмотря на то, что большинство операционных систем имеют каталоги appdata.