Java: нет изменений ArrayList извне классов

Я использую ArrayList в одном из классов моего проекта Java. Класс отслеживает, был ли список изменен, и предлагает несколько открытых методов для добавления и удаления элементов из списка, которые автоматически устанавливают переменную на "изменено".

Пока что список общедоступен, потому что я хочу, чтобы мой список был общедоступным для всех. Но я хочу, чтобы класс, которому принадлежит список, мог изменять его. Так что никаких модификаций со стороны классов. Это возможно? Если так, то как?

Обычно для контроля доступа вы, вероятно, используете методы получения и установки. Но даже с методом get и списком, установленным на private, другой класс мог бы делать getList().remove(element) и, таким образом, изменить список извне, не замечая, что список был изменен.

5 ответов

Решение

Сделайте ваше поле ArrayList закрытым, но верните его получателю Collections.unmodifiableList(list), что обеспечивает неизменяемый вид.

Это позволит внешнему коду обращаться с ним как с обычным списком, используя для каждого цикла и так далее, но отключит операции модификации. Кроме того, unmodifiableList возвращает представление в постоянное время.

Это буквально точный случай использования, для которого он был разработан. Javadoc:

Этот метод позволяет модулям предоставлять пользователям доступ "только для чтения" к внутренним спискам. Операции запроса в возвращаемом списке "считываются" в указанный список и пытаются изменить возвращенный список, будь то прямой или через его итератор, приводят к исключению UnsupportedOperationException.

Сделайте ваш список приватным и добавьте метод получения:

public List getList(){
    return new ArrayList(yourPrivateList);
}

Вы можете сделать ArrayList член приватный, и вместо получателя, который возвращает ArrayList, есть получатель, который принимает индекс i и возвращает iй элемент ArrayList,

public class Test
{
    private List<String> list = new ArrayList<String>();

    public getString (int i)
    {
        // you might want to add some validation of i here
        return list.get(i);
    }

}

getString позволяет пользователям вашего класса получить доступ к любому элементу списка без возможности его изменения.

Если вы хотите, чтобы ваши пользователи могли перебирать список без возможности его изменения, вы можете добавить getSize() метод для возврата размера списка (который позволил бы пользователям перебирать список, используя обычный цикл for), или ваш класс может реализовать Iterable (без поддержки операции удаления).

У вас есть несколько вариантов здесь:

  • Получатель, который возвращает ArrayList, может клонироваться перед возвратом объекта. Таким образом, даже если внешняя сущность изменяет объект, они в конечном итоге изменят клон, а не ваш исходный объект. Примечание. Операция клонирования может быть дорогостоящей. Я бы предложил вариант ниже.
  • использование Collections.unmodifiableList(..), Проверьте документацию здесь.
  • Или, как предлагают другие ответы: разверните свои собственные методы доступа и итерации.

Я думаю, что ваш лучший вариант здесь, чтобы сохранить List приватный и добавить метод получения, который возвращает копию List, но не List сам. Например:

public class EncapsulationTest {

    private List<Object> privateList = new ArrayList<Object>();

    // Your constructors and methods to track list
    // modification here ...

    public List<Object> getList() {
        // Maybe you need a null check here
        return new ArrayList<Object>(privateList);
    }

    public void addElement(Object newElement) {
        this.privateList.add(newElement);
        // Set your 'changed' variable to true
    }

    public void removeElement(Object element) {
        this.privateList.remove(element);
        // Set your 'changed' variable to true
    }
}

Если вы сделаете это, вы все равно можете прочитать точную копию List, но вы не можете изменить List сам. Ну, на самом деле вы можете изменить возвращенный List, но так как это другой объект, изменения не повлияют на ваш объект List,

Я надеюсь, что это помогает.

Другие вопросы по тегам