Java의 기본 배열에 대한 불변의 대안이 있습니까? 기본 배열을 만드는 final
것이 실제로 다음과 같은 일을 방해하지는 않습니다.
final int[] array = new int[] {0, 1, 2, 3};
array[0] = 42;
배열의 요소를 변경할 수 없도록하고 싶습니다.
int[]
및 new int[]
보다 입력 훨씬 쉽게 List<Integer>
와 new ArrayList<Integer>
? XD
Java의 기본 배열에 대한 불변의 대안이 있습니까? 기본 배열을 만드는 final
것이 실제로 다음과 같은 일을 방해하지는 않습니다.
final int[] array = new int[] {0, 1, 2, 3};
array[0] = 42;
배열의 요소를 변경할 수 없도록하고 싶습니다.
int[]
및 new int[]
보다 입력 훨씬 쉽게 List<Integer>
와 new ArrayList<Integer>
? XD
답변:
기본 배열에는 없습니다. List 또는 다른 데이터 구조를 사용해야합니다.
List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));
Arrays.asList
는 수정할 수 없습니다 . docs.oracle.com/javase/7/docs/api/java/util/… "지정된 배열이 지원하는 고정 크기 목록을 반환합니다. 반환 된 목록이"쓰기 "목록으로 변경됩니다."
Arrays.asList()
실제로 는 할 수 없다는 의미에서 수정할 수없는 것처럼 보입니다.add
또는 remove
반환의 항목 java.util.Arrays.ArrayList
( 혼동되지 않기 에 java.util.ArrayList
) -이 작업이 바로 실행되지 않습니다. 어쩌면 @mauhiz가 이것을 말하려고합니까? 그러나 물론 당신은 기존 요소를 수정할 수 List<> aslist = Arrays.asList(...); aslist.set(index, element)
있으므로 java.util.Arrays.ArrayList
확실히 수정할 수 는 없습니다 . QED 결과 asList
와 정상 의 차이를 강조하기 위해 주석을 추가했습니다ArrayList
내 권장 사항은 배열이나 unmodifiableList
를 사용하지 않고이 목적을 위해 존재 하는 Guava 의 ImmutableList 를 사용 하는 것입니다.
ImmutableList<Integer> values = ImmutableList.of(0, 1, 2, 3);
Collections.unmodifiableList
List를 변경할 수없는 것입니까?
다른 사람들이 지적했듯이 Java에서는 불변 배열을 가질 수 없습니다.
원래 배열에 영향을 미치지 않는 배열을 반환하는 메서드가 절대적으로 필요한 경우 매번 배열을 복제해야합니다.
public int[] getFooArray() {
return fooArray == null ? null : fooArray.clone();
}
분명히 게터를 호출 할 때마다 전체 사본을 만들므로 다소 비싸지 만 인터페이스를 변경할 수없는 경우 ( List
예를 들어 사용) 클라이언트가 내부를 변경할 위험이 없다면 필요할 수 있습니다.
이 기술을 방어 복사본 만들기라고합니다.
clone()
또는 Arrays.copy()
여기 에서 사용하는 것이 더 낫 습니까?
Java에서 불변 배열을 만드는 한 가지 방법이 있습니다.
final String[] IMMUTABLE = new String[0];
요소가 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
또 다른 대답
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"});
}
'java.lang.Integer'대신 네이티브 'int'가 (성능상의 이유로 또는 메모리를 절약하기 위해) 필요한 경우 자체 래퍼 클래스를 작성해야 할 것입니다. 인터넷에는 다양한 IntArray 구현이 있지만 Koders IntArray , Lucene IntArray 과 같은 변경 불가능한 것은 없습니다 . 아마도 다른 사람들이있을 것입니다.
Guava 22부터 패키지에서에 com.google.common.primitives
비해 메모리 풋 프린트가 더 작은 3 개의 새로운 클래스를 사용할 수 있습니다 ImmutableList
.
또한 빌더가 있습니다. 예:
int size = 2;
ImmutableLongArray longArray = ImmutableLongArray.builder(size)
.add(1L)
.add(2L)
.build();
또는 컴파일 타임에 크기가 알려진 경우 :
ImmutableLongArray longArray = ImmutableLongArray.of(1L, 2L);
이것은 Java 프리미티브에 대한 배열의 불변 뷰를 얻는 또 다른 방법입니다.
아니요, 불가능합니다. 그러나 다음과 같이 할 수 있습니다.
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);
이것은 래퍼를 사용해야하며 배열이 아닌 List이지만 List는 가장 가깝습니다.
valueOf()
. 오토 박싱이이를 처리합니다. 또한 Arrays.asList(0, 2, 3, 4)
훨씬 간결 할 것입니다.
valueOf()
는 내부 Integer 객체 캐시를 활용하여 메모리 소비 / 재활용을 줄이는 것입니다.
int
에 Integer
생각을; 다른 방법으로 조심해야합니다.
Java9 의 of (E ... elements) 메소드는 한 줄만 사용하여 불변 목록을 작성하는 데 사용할 수 있습니다.
List<Integer> items = List.of(1,2,3,4,5);
위의 메소드는 임의의 수의 요소를 포함하는 불변 목록을 리턴합니다. 이 목록에 정수를 추가하면 java.lang.UnsupportedOperationException
예외가 발생합니다. 이 메소드는 단일 배열을 인수로 허용합니다.
String[] array = ... ;
List<String[]> list = List.<String[]>of(array);
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()));
완벽하지는 않지만, 적어도 "의사 불변 배열"(클래스 관점에서)이 있으며 이것은 관련 코드를 손상시키지 않습니다.
음 .. 배열은 변형 매개 변수로 상수 (있는 경우)로 전달하는 데 유용합니다.
int[]
하면 호출자는 API 내부에 영향을주지 않고 해당 배열로 원하는 것을 수행 할 수 있다고 가정 할 수 있습니다.