Возврат константной ссылки массива - PullRequest
15 голосов
/ 24 ноября 2010

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

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

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

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

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

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


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

Ответы [ 5 ]

23 голосов
/ 24 ноября 2010

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

Ваш

return arrayList;

становится

return Collections.unmodifiableList(arrayList);

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

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

2 голосов
/ 24 ноября 2010

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

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

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

  • Возвращает неизменный объект:

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

0 голосов
/ 23 февраля 2013

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

    return your_private_array.clone();

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

0 голосов
/ 19 марта 2011

Вы также можете использовать 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(), потому что это хорошая практикавозвращать пустые коллекции вместо нулевых значений ( Шаблон нулевого объекта ).Вы можете подумать, что это создает ненужную реализацию объекта, но ImmutableList.of() фактически возвращает синглтон.
0 голосов
/ 24 ноября 2010

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

...