Copying Arrays in Java 6-2

자바 6에서는 더 이상 이런 역할의 유틸리티 메소드가 필요가 없다. 썬은 배열의 복사를 위한 직접 지원을 소개한다. 썬은 새로운 Arrays 클래스의 오버로드된 메소드인 copyOf 를 정의한다.

1
targetArray = Arrays.copyOf(sourceArray, length);

여기서는 copyOf 메소드의 행동을 시연해보기 위해 JUnit test를 몇 개 사용하였다. 여기에 기본 기능을 보여주는 첫번째 테스트가 있다.

1
2
3
4
5
6
@Test
public void genericArrayCopyOf() {
Number[] source = { new Double(5.0), new Double(10.0) };
Number[] target = Arrays.copyOf(source, source.length);
assertEquals(source, target);
}

JUnit 4의 새로운 특징중의 하나는 assertEquals를 사용한 두개의 배열의 비교 능력이다. 그 작업을 할 때, JUnit는 첫째로 각 배열의 크기를 비교한다. 만약 두 배열이 같다면 JUnit은 equals을 사용하여 각각의 요소들을 비교한다. 두 배열이 다르면, JUnit은 failure 메시지를 나타내어 부등호 값을 보여준다.

자바는 두개의 다른 변수로 기본형 타입을 지원을 위해 copyOf 를 오버로드한다. 또 다른 테스트는 원본의 범위를 지원할 수 있는 방법을 보여준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void copyOfWithRange() {
String[] source = { "0", "1", "2", "3", "4" };
String[] target = Arrays.copyOfRange(source, 2, 4);
assertEquals(new String[] { "2", "3" }, target);
}
@Test
public void primitives() {
int[] source = { 0, 1, 2, 3, 4 };
int[] target = Arrays.copyOfRange(source, 4, 5);
assertEqualsPrim(new int[] { 4 }, target);
}

JUnit 4는 기본형 타입을 가지고 있는 두 배열을 비교할 수 없기에 assertEqualsPrim 메소드를 작성했다. It contains only a version that compares two Object arrays. assertEquals 를 이용해 두 기본형 타입의 배열을 비교하는 것은 자바가 메모리 비교를 하는 것을 의미한다. 별거 아니게, assertEqualsPrim 를 작성하는 것은 아주 쉽다.

1
2
3
4
5
6
7
8
9
10
11
12
13
static void assertEqualsPrim(int[] expected, int[] actual) {
if (expected.length != actual.length)
fail(String.format("expected length = %s, actual length = %s",
expected.length, actual.length));
for (int i = 0; i < expected.length; i++) {
if (expected[i] != actual[i])
fail(String.format(
"mismatch at index %d: expected [%s] but was [%s]", i,
expected[i], actual[i]));
}
}

What if I want the new array to be of a new, subclass type? The following test fails:

1
2
3
4
5
6
@Test
public void genericArrayCopyOfWithNewType() {
Number[] source = { new Double(5.0), new Double(10.0) };
Double[] target = (Double[])Arrays.copyOf(source, source.length);
assertEquals(source, target); // fail!
}

But Java 6 allows me to declare a new type for the target array on a copy:

1
2
3
4
5
6
@Test
public void genericArrayCopyOfWithNewType() {
Number[] source = { new Double(5.0), new Double(10.0) };
Double[] target = Arrays.copyOf(source, source.length, Double[].class);
assertEquals(source, target);
}
Share Comments

Moon Night

OpenGL 레포트였던 밤하늘에 떠있는 달과 별을 그려보았다.

별의 좌표는 랜덤으로 주어지고, 달은 원의 좌표를 계산하여 그렸다.

지형은 일직선을 재귀적으로 쪼개서 각도를 변경하여 그렸다.

void setup(){
    size(300, 240, P2D);
    background(0);

    noLoop();
    noStroke();
}

void draw(){

    drawSky();      
    drawStars(50);      
    drawEclipse();      
    drawMountain(height / 1.5);
}

void drawSky(){

    // gradient
    color night = color(0, 0, 125);
    color glow = color(255, 102, 0);

    for(int i = 0; i < height; i++){
    float rate = map(i, 0, height, 0, 1);
    color c = lerpColor(night, glow, rate);
    stroke(c);
    line(0, i, width, i);
    }
}

void drawStars(int num){

    stroke(255);

    for(int i = 0; i < num; i++){
    int x = random(width);
    int y = random(height / 2);

    point(x, y);
    }
}

void drawEclipse(){

    noStroke();

    color yellow = color(255, 255, 0);    
    fill(yellow);

    int cx = width / 2;
    int cy = width / 4;
    int r = 30;

    beginShape();

    for(int i = -45; i < 135; i++){
    int x = cx + r * cos(radians(i));
    int y = cy + r * sin(radians(i));

    vertex(x, y);
    }

    for(int i = 135; i > -45; i--){        
    int x = cx - 10 + r * cos(radians(i));
    int y = cy - 10 + r * sin(radians(i));

    vertex(x, y);
    }

    endShape(CLOSE);
}

void drawMountain(int tall){

    beginShape();

    vertex(0, height);
    vertex(0, tall);

    breakLine(0, tall, width, tall);

    vertex(width, tall);
    vertex(width, height);

    endShape(CLOSE);
}

void breakLine(int x0, int y0, int x1, int y1){
    float dist = sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2));

    if(dist < 30){
    return;
    }

    // mid point
    int cx = x0 + (x1 - x0) / 2;
    int cy = y0 + (y1 - y0) / 2;

    int x2 = cx + (dist / 8) * cos(QUARTER_PI * random(8));
    int y2 = cy + (dist / 8) * sin(QUARTER_PI * random(8));

    breakLine(x0, y0, x2, y2);

    vertex(x2, y2);

    breakLine(x2, y2, x1, y1);
}
Share Comments

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

혜화동

본인들의 의지와는 다르게 아이를 입양보낸 젊은 남녀가 아이를 찾아가는 과정을 그린 영화이다.

생명의 소중함과 책임에 대한 메시지를 던져주고 있다.

극중 주인공인 ‘혜화’ 역할에 배우 유다인의 표정 연기가 영화의 메시지를 더욱 강하게 전달할 수 있도록 만들어주는 듯 하다.

Share Comments

Magician Justin Willman on the Ellen Show

두 가지 마술을 보여주는데 루틴이라기 보단 그냥 하나씩 따로따로 ㅋㅋ

그래도 재미있는 마술이다 ㅎㅎ

Share Comments

Captain America the First Avenger

캡틴 아메리카의 탄생 비화를 설명해주는 스토리이다.

어벤저스를 먼저보고 보았기에 마지막 장면에서 이제 어벤저스 팀을 모으는구나 생각되었다.

마블 코믹스의 만화에 관심이 더 생겼다.

Share Comments

마르코 템페스트 Marco Tempest 독특한 사이버 카드 마술사

과학기술과 마술을 접목하는 것으로 유명한 마르코 템페스트의 TED 영상 중 하나이다.

증강현실과 스토리텔링을 카드 마술에 접목하였다.

마술에서의 새로운 분야를 개척하는 대단한 인물임에 틀림이 없다.

Share Comments

Jack the Giant Slayer

잭과 콩나무 이야기를 각색한 영화이다.

사실 원화의 내용은 기억나지 않기에 비교 불가능;;

중세 판타지를 배경으로 화끈한 액션이 볼만했다.

Share Comments

의뢰인

아내를 죽인 살인용의자를 중심으로 검사와 변호사의 대립을 다룬 영화이다.

예전에 본 영화인데 기억이 안나서 다시 보았다.

하정우, 박희순, 장혁. 세 주연 배우들의 두뇌 싸움. 재미있었다.

Share Comments