Java中的不可变数组

150 java arrays immutability

Java中的原始数组是否有一个不可变的替代方法?制作一个原始数组final实际上并不能阻止人们做类似的事情

final int[] array = new int[] {0, 1, 2, 3};
array[0] = 42;
Run Code Online (Sandbox Code Playgroud)

我希望数组的元素不可更改.

Jas*_*n S 158

不是原始数组.您需要使用List或其他一些数据结构:

List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));
Run Code Online (Sandbox Code Playgroud)

  • 我不知道Arrays.asList(T ...).我想我现在可以摆脱我的ListUtils.list(T ...). (18认同)
  • @mauhiz`Arrays.asList`是*不*不可修改.http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#asList(T ...)"返回由指定数组支持的固定大小列表.(对返回列表"直写"到数组.)" (10认同)
  • @JasonS好吧,`Arrays.asList()`确实_seems_不可修改的意思是你不能`添加`或`删除`返回的`java.util.Arrays.ArrayList`项目(**不要混淆**与`java.util.ArrayList`) - 这些操作没有实现.也许@mauhiz试图这样说?但是当然你可以使用`List <> aslist = Arrays.asList(...)修改现有元素; aslist.set(index,element)`,所以`java.util.Arrays.ArrayList`当然不是**不可用**,QED添加注释只是为了强调`asList`和normal的结果之间的区别`ArrayList` (6认同)
  • 顺便说一下,Arrays.asList给出了一个不可修改的列表 (3认同)
  • @tony表示ArrayList不是java.util的 (3认同)
  • @mauhiz,不,不是根据源,Arrays.asList(array)返回一个新的ArrayList <>(数组),它具有完全有效的set方法... (2认同)

Col*_*inD 73

我的建议是不使用数组或unmodifiableList使用GuavaImmutableList,它就是为此而存在的.

ImmutableList<Integer> values = ImmutableList.of(0, 1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

  • ImmutableList通常*更好(取决于用例),因为它是不可变的.Collections.unmodifiableList不是不可变的.相反,它是接收器无法改变的观点,但原始源可以改变. (29认同)
  • +1 Guava的ImmutableList甚至比Collections.unmodifiableList更好,因为它是一个单独的类型. (3认同)
  • @CharlieCollins,如果没有办法访问原始源而不是`Collections.unmodifiableList`足以使List不可变? (2认同)

Joa*_*uer 20

正如其他人所说,你不能在Java中拥有不可变数组.

如果您绝对需要一个返回不影响原始数组的数组的方法,那么每次都需要克隆该数组:

public int[] getFooArray() {
  return fooArray == null ? null : fooArray.clone();
}
Run Code Online (Sandbox Code Playgroud)

显然这是相当昂贵的(因为你每次调用getter时都会创建一个完整的副本),但是如果你不能改变界面(List例如使用一个)并且不能让客户改变你的内部风险,那么它可能是必要的.

这种技术被称为制作防御性副本.

  • @Erik:他没有,但这是不可变数据结构的一个非常常见的用例(我修改了答案以引用一般的方法,因为解决方案适用于所有地方,即使它在getter中更常见). (6认同)
  • 在这里使用`clone()`或`Arrays.copy()`会更好吗? (6认同)
  • 他在哪里提到他需要一个吸气剂? (3认同)
  • 第 13 条的最后一句“明智地覆盖克隆”:“通常,复制功能最好由构造函数或工厂提供。该规则的一个显着例外是数组,最好使用 clone 方法复制它。” (3认同)

Bri*_*ham 14

有一种方法可以在Java中创建不可变数组:

final String[] IMMUTABLE = new String[0];
Run Code Online (Sandbox Code Playgroud)

具有0个元素(显然)的数组不能变异.

如果您使用该List.toArray方法将a转换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
Run Code Online (Sandbox Code Playgroud)

  • 但这无助于OP实现包含数据的不可变数组. (3认同)
  • @Sridhar-Sarnobat 这就是答案的要点。Java 中没有办法创建一个包含数据的不可变数组。 (2认同)

rmu*_*ler 9

从Java 9,你可以用List.of(...)的JavaDoc

这个方法返回一个不可变的List并且非常有效。


aer*_*ode 5

另一个答案

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"});
}
Run Code Online (Sandbox Code Playgroud)


Jea*_*ean 5

从 Guava 22 开始,com.google.common.primitives您可以从包中使用三个新类,与ImmutableList.

他们还有一个建筑商。例子:

int size = 2;
ImmutableLongArray longArray = ImmutableLongArray.builder(size)
  .add(1L)
  .add(2L)
  .build();
Run Code Online (Sandbox Code Playgroud)

或者,如果大小在编译时已知:

ImmutableLongArray longArray = ImmutableLongArray.of(1L, 2L);
Run Code Online (Sandbox Code Playgroud)

这是获取 Java 原语数组的不可变视图的另一种方法。