Неизменяемый массив в Java

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

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

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

4b9b3361

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

List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));
128
ответ дан 13 сент. '10 в 16:45
источник

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

ImmutableList<Integer> values = ImmutableList.of(0, 1, 2, 3);
65
ответ дан 13 сент. '10 в 17:27
источник

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

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

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

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

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

16
ответ дан 13 сент. '10 в 16:53
источник

Существует один способ создания неизменяемого массива в 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
11
ответ дан 14 авг. '12 в 23:51
источник

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

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
ответ дан 14 мая '13 в 16:52
источник

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

3
ответ дан 13 сент. '10 в 17:49
источник

Так как 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.

2
ответ дан 24 мая '17 в 11:00
источник

В некоторых ситуациях легче использовать этот статический метод из библиотеки 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})
1
ответ дан 16 июля '13 в 15:49
источник

Нет, это невозможно. Однако можно было бы сделать что-то вроде этого:

List<Integer> temp = new ArrayList<Integer>();
temp.add(Integer.valueOf(0));
temp.add(Integer.valueOf(2));
temp.add(Integer.valueOf(3));
temp.add(Integer.valueOf(4));
List<Integer> immutable = Collections.unmodifiableList(temp);

Для этого требуется использование оберток и является списком, а не массивом, но наиболее близким вам будет.

1
ответ дан 13 сент. '10 в 16:46
источник

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

1
ответ дан 25 июля '13 в 21:41
источник

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

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

1
ответ дан 25 окт. '17 в 8:32
источник

метода (E... elements) в Java9 можно использовать для создания неизменяемого списка, используя просто строка:

List<Integer> items = List.of(1,2,3,4,5);

Вышеупомянутый метод возвращает неизменный список, содержащий произвольное количество элементов. И добавление любого целого в этот список приведет к исключению java.lang.UnsupportedOperationException. Этот метод также принимает один массив в качестве аргумента.

String[] array = ... ;
List<String[]> list = List.<String[]>of(array);
0
ответ дан 14 дек. '17 в 18:51
источник

Хотя верно, что Collections.unmodifiableList() работает, иногда у вас может быть большая библиотека, имеющая уже определенные методы для возврата массивов (например, String[]). Чтобы предотвратить их разбиение, вы можете определить вспомогательные массивы, которые будут хранить значения:

public class Test {
    private final String[] original;
    private final String[] auxiliary;
    /** constructor */
    public Test(String[] _values) {
        original = new String[_values.length];
        // Pre-allocated array.
        auxiliary = new String[_values.length];
        System.arraycopy(_values, 0, original, 0, _values.length);
    }
    /** Get array values. */
    public String[] getValues() {
        // No need to call clone() - we pre-allocated auxiliary.
        System.arraycopy(original, 0, auxiliary, 0, original.length);
        return auxiliary;
    }
}

Чтобы проверить:

    Test test = new Test(new String[]{"a", "b", "C"});
    System.out.println(Arrays.asList(test.getValues()));
    String[] values = test.getValues();
    values[0] = "foobar";
    // At this point, "foobar" exist in "auxiliary" but since we are 
    // copying "original" to "auxiliary" for each call, the next line
    // will print the original values "a", "b", "c".
    System.out.println(Arrays.asList(test.getValues()));

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

0
ответ дан 22 июля '14 в 16:30
источник

Ну... массивы полезны для передачи в качестве констант (если они были) в качестве параметров параметров.

-3
ответ дан 18 февр. '11 в 13:24
источник