Неизменяемый массив в Java - PullRequest
141 голосов
/ 13 сентября 2010

Есть ли неизменная альтернатива примитивным массивам в Java? Создание примитивного массива final на самом деле не мешает делать что-то вроде

final int[] array = new int[] {0, 1, 2, 3};
array[0] = 42;

Я хочу, чтобы элементы массива были неизменяемыми.

Ответы [ 14 ]

154 голосов
/ 13 сентября 2010

Не с примитивными массивами.Вам нужно будет использовать список или другую структуру данных:

List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));
70 голосов
/ 13 сентября 2010

Я рекомендую не использовать массив или unmodifiableList, а использовать Guava ImmutableList , который существует для этой цели.

ImmutableList<Integer> values = ImmutableList.of(0, 1, 2, 3);
20 голосов
/ 13 сентября 2010

Как уже отмечали другие, у вас не может быть неизменных массивов в Java.

Если вам абсолютно необходим метод, который возвращает массив, который не влияет на исходный массив, то вам нужно будет клонироватьмассив каждый раз:

public int[] getFooArray() {
  return fooArray == null ? null : fooArray.clone();
}

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

Этот метод называется созданием защитной копии.

14 голосов
/ 15 августа 2012

Существует один способ сделать неизменный массив в Java:

final String[] IMMUTABLE = new String[0];

Массивы с 0 элементами (очевидно) не могут быть изменены.

Это может пригодиться, если вы используете метод List.toArray для преобразования List в массив. Поскольку даже пустой массив занимает некоторую память, вы можете сохранить это выделение памяти, создав постоянный пустой массив и всегда передавая его методу toArray. Этот метод будет выделять новый массив, если переданному массиву не хватает места, но если он есть (список пуст), он вернет переданный вами массив, что позволит вам повторно использовать этот массив при каждом вызове toArray на пустом List.

final static String[] EMPTY_STRING_ARRAY = new String[0];

List<String> emptyList = new ArrayList<String>();
return emptyList.toArray(EMPTY_STRING_ARRAY); // returns EMPTY_STRING_ARRAY
5 голосов
/ 14 мая 2013

Еще один ответ

static class ImmutableArray<T> {
    private final T[] array;

    private ImmutableArray(T[] a){
        array = Arrays.copyOf(a, a.length);
    }

    public static <T> ImmutableArray<T> from(T[] a){
        return new ImmutableArray<T>(a);
    }

    public T get(int index){
        return array[index];
    }
}

{
    final ImmutableArray<String> sample = ImmutableArray.from(new String[]{"a", "b", "c"});
}
4 голосов
/ 25 октября 2017

Начиная с Java 9, вы можете использовать List.of(...), JavaDoc .

Этот метод возвращает неизменный List и очень эффективен.

3 голосов
/ 13 сентября 2010

Если вам нужен (по соображениям производительности или для экономии памяти) нативный 'int' вместо 'java.lang.Integer', то вам, вероятно, потребуется написать собственный класс-оболочку. В сети есть различные реализации IntArray, но ни одна (я обнаружил) не была неизменной: Koders IntArray , Lucene IntArray . Возможно, есть и другие.

2 голосов
/ 24 мая 2017

Начиная с Guava 22, из пакета com.google.common.primitives вы можете использовать три новых класса, которые занимают меньше памяти по сравнению с ImmutableList.

У них также есть строитель.Пример:

int size = 2;
ImmutableLongArray longArray = ImmutableLongArray.builder(size)
  .add(1L)
  .add(2L)
  .build();

или, если размер известен во время компиляции:

ImmutableLongArray longArray = ImmutableLongArray.of(1L, 2L);

Это еще один способ получения неизменяемого представления массива для примитивов Java.

1 голос
/ 25 июля 2013

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

1 голос
/ 16 июля 2013

В некоторых ситуациях использование статического метода из библиотеки Google Guava будет легче: List<Integer> Ints.asList(int... backingArray)

Примеры:

  • List<Integer> x1 = Ints.asList(0, 1, 2, 3)
  • List<Integer> x1 = Ints.asList(new int[] { 0, 1, 2, 3})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...