Copying Arrays in Java 6-1

자바 언어는 몇몇 대단한 유물을 가지고 있다. 예를 들어, 스위치 구문은 아직도 스트링 오브젝트를 스위칭하는 개념을 지원하지 않는다. (그러나 switch 구문은 이넘 타입을 지원하는 것으로 업데이트 되었다.) 그 이유는 과거로 돌아가 원래 C에서 디자인된 switch 구문의 개념에서 나타난다. 이유가 무엇이든, 내가 필요로 했던 스위치문에서의 스트링 사용은 불행하게도 불가능하다는 것을 알게되었다.

한 배열에서 다른 배열로 내용을 빠르게 복사하기 위해 사용되는 System.arraycopy 메소드도 비슷한 legacy를 기초로 하고 있는 것으로 보인다. 이 메소드의 이름조차 옛 스타일의 C 함수인 memcpy 와 비슷하다. 이 같은 자바에서의 배열 복사 방법은 사람들 사이에서 선호되었고, 처음 출시 후로 전혀 변하지 않았다.

arraycopy 메소드는 시스템에서 정의된 정적 메소드로서 확실히 충분하게 강력하다. 시스템 클래스는 하나의 범용의 메소드를 제공한다.

1
System.arraycopy(sourceArray, sourceStartIndex, targetArray, targetStartIndex, length);

arraycopy 메소드는 단순히 원본 배열의 요소들 전체를 대상 배열로 복사하는 것보다 많은 것을 제공한다. 게다가, arraycopy는 원본과 대상의 시작 인덱스를 허용하고, 복사할 요소들의 수를 나타내는 length 또한 허용한다.

나의 경우에 항상 쓰지는 않지만, 이런 추가적인 유연성은 널리 사용된다. 예를 들어 ArrayList 클래스는 배열 내용을 이동시킬때, 사용자가 배열의 중간에 요소를 삽입하고 싶을 때 arraycopy 를 사용한다.

대부분의 경우, 일부분이 아닌 전체 배열을 복사하고 싶음에도 불구하고, 내가 배열 형태로 요소들을 시프트 시킬 일을 자주 없었다. 내가 System.arrayCopy를 사용하는 대부분의 방식은 코드 두줄이면 된다.

1
2
3
String[] source = { "alpha", "beta", "gamma" };
String[] target = new String[source.length];
System.arraycopy(source, 0, target, 0, source.length);

이렇게 간단하고 자주 필요한 것에서도, 자바는 너무 많은 코드를 사용한다는 생각이 든다. 만약 이런 구성을 주어진 애플리케이션에서 여러 번 사용하게 된다면, 나는 재사용 가능한 메소드를 원할 것이다.

1
2
3
4
5
private final <T> T[] copy(T[] source) {
T[] target = new T[source.length]; // This will not compile!
System.arraycopy(source, 0, target, 0, source.length);
return target;
}

음… 안되네. 컴파일하면 에러메시지가 나타난다.

1
Cannot create a generic array of T

리플렉션을 이용해 이 에러의 원인을 얻을 수 있다. 이것이 copy 메소드를 만든 코드이다.

1
2
3
4
5
6
private final <T> T[] copy(T[] source) {
Class type = source.getClass().getComponentType();
T[] target = (T[])Array.newInstance(type, source.length);
System.arraycopy(source, 0, target, 0, source.length);
return target;
}

자바 컴파일러는 newInstance 를 호출함에 있어서 “Type safety: the case from Object to T[] is actually checking against the erased type Object[].” 경고를 주어 주의를 표시한다. 리플렉션을 이용한다는 것은 컴파일러가 이것이 잘못된 캐스트인지 알려주는 정보가 충분하지 않다는 것을 의미한다. 더 나은 해결책이 있다면, 단순한 라우팅과 성가신 경고를 억제하는 것을 취한다.

1
2
3
4
5
6
7
8
9
10
@SuppressWarnings("unchecked")
private final <T> T[] copy(T[] source) {
Class type = source.getClass().getComponentType();
T[] target = (T[])Array.newInstance(type, source.length);
System.arraycopy(source, 0, target, 0, source.length);
return target;
}
String[] source = { "alpha", "beta", "gamma" };
String[] target = copy(source);

여기서 보인 것처럼, 재빠르게 범용적인 배열 복사 유틸리티 메소드를 만들 수 있다.

Share Comments