Представь, что у меня есть этот класс:
public class Test
{
private String[] arr = new String[]{"1","2"};
public String[] getArr()
{
return arr;
}
}
Теперь у меня есть другой класс, который использует вышеупомянутый класс:
Test test = new Test();
test.getArr()[0] ="some value!"; //!!!
Вот в чем проблема: я получил доступ к закрытому полю класса извне! Как я могу предотвратить это? Я имею в виду, как я могу сделать этот массив неизменным? Означает ли это, что с каждым методом получения вы можете получить доступ к приватному полю? (Я не хочу никаких библиотек, таких как гуава. Мне просто нужно знать правильный способ сделать это).
final
действительно предотвратить модификацию поля . Однако предотвращение модификацииObject
упомянутого поля является более сложным.Ответы:
Вы должны вернуть копию вашего массива.
источник
Unmodifiable List
.Если вы можете использовать List вместо массива, Collections предоставит неизменяемый список :
источник
Collections.unmodifiableList(list)
качестве назначения для поля, чтобы убедиться, что список не изменен самим классом.String
есть, но если они являются изменяемыми, возможно, необходимо что-то сделать, чтобы предотвратить изменение их вызывающей стороной.Модификатор
private
защищает только само поле от доступа к другим классам, но не ссылки на объекты этим полем. Если вам нужно защитить указанный объект, просто не выдавайте его. + Изменитьчтобы:
или
источник
Это
Collections.unmodifiableList
уже упоминалось - какArrays.asList()
ни странно! Мое решение также будет использовать список извне и обернуть массив следующим образом:Проблема с копированием массива: если вы делаете это каждый раз, когда получаете доступ к коду, а массив большой, вы наверняка создадите много работы для сборщика мусора. Таким образом, копия - простой, но очень плохой подход - я бы сказал, «дешево», но дорого! Особенно, когда у вас больше, чем просто 2 элемента.
Если вы посмотрите на исходный код
Arrays.asList
иCollections.unmodifiableList
там на самом деле не так много создано. Первый просто оборачивает массив, не копируя его, второй просто оборачивает список, делая изменения в нем недоступными.источник
immutableList
все!Arrays.asList
иCollections.unmodifiableList
операции, вероятно , дешевле для больших массивов. Может быть, кто-то может подсчитать, сколько элементов необходимо, но я уже видел код в циклах for с массивами, содержащими тысячи элементов, копируемых просто для предотвращения модификации - это безумие!Вы также можете использовать,
ImmutableList
который должен быть лучше, чем стандартunmodifiableList
. Этот класс является частью библиотек Guava , созданных Google.Вот описание:
Вот простой пример того, как его использовать:
источник
Test
классу, чтобы оставить возвращенный список без изменений . Вы должны убедиться, чтоImmutableList
это возвращается, и что элементы списка также являются неизменяемыми. В противном случае мое решение также должно быть безопасным.с этой точки зрения вы должны использовать копию системного массива:
источник
clone
и не так краток.Вы можете вернуть копию данных. Звонящий, который решит изменить данные, будет только менять копию
источник
Суть проблемы в том, что вы возвращаете указатель на изменяемый объект. К сожалению. Либо вы делаете объект неизменным (решение с неизменяемым списком), либо вы возвращаете копию объекта.
В целом, окончательность объектов не защищает объекты от изменения, если они изменчивы. Этими двумя проблемами являются «поцелуи двоюродных братьев».
источник
Возвращение неизменяемого списка - хорошая идея. Но список, который становится неизменяемым во время вызова метода получателя, все еще может быть изменен классом или классами, производными от класса.
Вместо этого вы должны дать понять любому, кто расширяет класс, что список не следует изменять.
Так что в вашем примере это может привести к следующему коду:
В приведенном выше примере я сделал
STRINGS
поле общедоступным, в принципе вы можете покончить с вызовом метода, так как значения уже известны.Вы также можете назначить строки
private final List<String>
полю, которое нельзя изменить во время создания экземпляра класса. Использование константы или аргументов экземпляра (конструктора) зависит от дизайна класса.источник
Да, вы должны вернуть копию массива:
источник