Возвращение константной ссылки массива

Я действительно восхищаюсь функциями Java и не хочу отказываться от использования его для решения следующей проблемы:

У меня есть класс, который может быть унаследован, и внутри него есть private ArrayList arr; Так что функция setter в порядке, но функция getter return arr; возвращает ссылку на ту переменную, которую любой, способный редактировать весь этот массив, который я не хочу и приватный, не будет иметь никакого смысла!

В С ++ я бы просто return const arr; и он будет возвращать постоянную ссылку на переменную.

Мне так нужно, чтобы переменная не была клонирована или скопирована вручную, потому что существует так много вычислений, которые требуют (ЧИТАЙТЕ ТОЛЬКО переменную) ПОЧЕМУ нет возврата const в java???? Могу ли я избежать копирования?

п.с. (final ArrayList<Integer> arr;) не является опцией, так как массив всегда меняет размер или значения элемента.

Если я не смог найти решение этой проблемы, я угрожаю вернуться на C++ или обнародовать все, и вы никогда не получите мое программное обеспечение:D


РЕДАКТИРОВАТЬ: еще один важный вопрос: я спрашиваю о чем-то, что не очень хорошо (с точки зрения разработки программного обеспечения), я имею в виду, если создатели JAVA думали, что у них нет константной ссылки (возвращая ссылки только для чтения), то я должен просить что-то, что может быть обработано в другом путь. или мой дизайн программы не так, я так запутался.

5 ответов

Решение

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

Ваш

return arrayList;

становится

return Collections.unmodifiableList(arrayList);

К сожалению, ограничения только для чтения не будут выполняться компилятором. Однако они будут применяться во время выполнения.

Вам также доступны: unmodifiableSet, unmodifiableMap, unmodifiableCollection, unmodifiableSortedSet и unmodifiableSortedMap. И если этого недостаточно, вы все равно можете черпать вдохновение из этого общего подхода к проектированию и создавать свои собственные классы-оболочки только для чтения.

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

  • Не раскрывайте getter, предоставляйте только те методы, которым разрешено вызывать, например

    public void addToList(Object arg) { this.arr.add(arg);}

  • Вернуть неизменный объект:

    public List getArr() { return Collections.unmodifiableList(this.arr); }

Существует альтернатива методу unmodifiableList. Вы можете просто вернуть копию этого частного массива. Например,

    return your_private_array.clone();

Ну, это может быть потеря производительности за это. Но у вас есть неизменный интерфейс (вы все равно возвращаете массив).

Вы также можете использовать неизменные коллекции Google Guava. В этом случае вы должны хранить ImmutableList в своем поле.

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

Но прекрасно, когда вы знаете, что Список не изменится после постройки объекта.

Неизменный пример (список не изменится после постройки объекта)

@Immutable
public final class Foo {

    @Nonnull
    private final ImmutableList<String> list;

    public Foo(@Nonnull List<String> list) {
        // you could also compute the appropriate list here
        // before assigning it to the field
        this.list = ImmutableList.copyOf(list);
    }


    public ImmutableList<String> getList() {
        return list;
    }
}

Изменяемый пример (список может быть изменен только с помощью установщика)

public class Foo {

    @Nonnull
    private ImmutableList<String> list = ImmutableList.of();

    public ImmutableList<String> getList() {
        return list;
    }

    public void setList(@Nonnull List<String> list) {
        this.list = ImmutableList.copyOf(list);
    }
}

замечания

  • Я знаю, что часто советуют, чтобы методы возвращали максимально общий тип (List в этом случае), но я предпочитаю объявлять тип возвращаемого значения моего получателя как ImmutableListпотому что он действует как документация (нет необходимости документировать неизменяемость возвращаемого списка в Javadoc) и как контракт API. Это все равно что сказать: "Я гарантирую, что этот список будет неизменным, вам не нужно беспокоиться или защищать его". И это очень лаконично.
  • ImmutableList.copyOf() отлично, так как он автоматически отклоняет нулевые списки (бросая NullPointerException). Это также отклоняет нулевые элементы. И он не будет копировать список источников, если это уже ImmutableList, что позволяет избежать бесполезного создания объектов.
  • Во втором примере я инициализирую поле пустым ImmutableList, используя ImmutableList.of()потому что это хорошая практика, чтобы возвращать пустые коллекции вместо нулевых значений ( шаблон Null Object). Вы можете подумать, что это создает ненужную реализацию объекта, но ImmutableList.of() на самом деле возвращает синглтон.

unmodifiableList - определенно ответ.

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