6.3 배열의 참조

JAVA PROGRAMMING/JAVA 2010/02/21 21:19 by 킨테리 KinTeL


6.3.1 배열의 참조



이 절에서는 배열의 사용법에 대해서 약간 더 구체적으로 알아보겠습니다. 배열의 복사에서 우리는 다음과 같은 구문을 사용했습니다.

▣ 배열끼리의 할당
◈ int[] ar1 = new int[]{0,1,2,3,4,5,6,7,8,9};
◈ int[] ar2 = ar1;

배열끼리의 할당에서 참조값복사가 이루어집니다. ar2에 ar1이 가지고 있던 참조값이 복사된 것입니다. 이 때 ar1으로 작업을 하든 ar2로 작업을 하든 동일한 결과를 얻을 수 있습니다. 즉 배열은 객체이기 때문에 객체의 참조값만 가지고 있으면 해당 객체를 핸들할 수 있습니다.

▣ 객체의 참조값
◈ 객체의 참조값만 있으면 해당 객체를 핸들할 수 있다.

직접적인 배열끼리의 할당 이외에도 배열이 매개변수로 전달될 경우에도 참조값복사가 일어납니다. 다음은 배열이 매개변수로 전달될 때 참조값복사가 일어나는 예를 보여주고 있습니다.

◈ public int sum(int[] temp){
◈         //...
◈ }
◈ int[] ar = new int[]{0,1,2,3,4,5,6,7,8,9};

▣ 배열이 메서드의 매개변수로 사용될 때
◈ sum(ar); //메서드 호출
◈ ar이 매개변수로 전달될 때 참조값복사 발생
  
sum(ar)을 호출할 때 배열을 매개변수로 전달하는 과정에서 참조값복사가 일어나는 것입니다. 배열이 매개변수로 사용될 때 참조값복사가 일어나는 과정을 그림으로 나타내면 다음과 같습니다.

매개변수의 참조값복사【chap06\arrayparamcopy.bmp】
 


   

위의 그림에서 sum(ar)을 호출하는 순간 다음과 같은 구문이 성립합니다.

▣ 참조값복사
◈ int[] temp = ar; //매개변수로 전달 될 때

배열이 매개변수로 전달될 때 위와 같은 참조값복사가 일어나는 것입니다. 그렇기 때문에 temp에서는 참조값 10001을 갖게 되고, 10001을 이용해서 다시 주소 FFFF:07CA를 찾아가서 실제 메모리에 접근하는 것입니다.

위에서 제시한 직접 할당을 이용한 참조값복사와 매개변수를 이용한 참조값복사를 예제로 작성해 보도록 하겠습니다.



6.3.2 배열 할당의 참조



배열은 객체입니다. 배열의 이름은 참조변수입니다. 배열끼리 할당한다면 참조값복사에 의해서 배열의 참조값이 복사되어지고 같은 메모리를 참조하게 됩니다. 이는 객체변수들의 기본적인 특징이며 배열도 예외는 아닙니다. 다음은 배열의 이름이 참조변수라는 것을 증명해 주는 예제입니다.

『chap06\ArrayRefMain.java』
ⓙ───────────────────────────────────────
/**
배열의 참조값 할당을 테스트하는 예제
**/
public class ArrayRefMain {
    public static void main(String[] args) {
        ArrayRefMain ar = new ArrayRefMain();
        int[] aref  = new int[]{0,1,2,3};
        int[] bref = aref;
        int[] cref = bref;
        //참조값 출력
        System.out.println("aref=" + aref);
        System.out.println("bref=" + bref);
        System.out.println("cref=" + cref);
        //aref[0]에 10을 할당한 후 aref, bref, cref 출력하기
        aref[0]=10;
        for(int i=0; i<aref.length; i++) {
            System.out.print("aref[" + i + "]=" + aref[i] +"\t");
            System.out.print("bref[" + i + "]=" + bref[i] +"\t");
            System.out.println("cref[" + i + "]=" + cref[i]);
        }
        System.out.println();
        //bref[1]에 11을 할당한 후 aref, bref, cref 출력하기
        bref[1] = 11; 
        for(int i=0; i<bref.length; i++) {
            System.out.print("aref[" + i + "]=" + aref[i] +"\t");
            System.out.print("bref[" + i + "]=" + bref[i] +"\t");
            System.out.println("cref[" + i + "]=" + cref[i]);
        }
        System.out.println();
        //cref[2]에 12을 할당한 후 aref, bref, cref 출력하기
        cref[2] = 12; 
        for(int i=0; i<cref.length; i++) {
            System.out.print("aref[" + i + "]=" + aref[i] +"\t");
            System.out.print("bref[" + i + "]=" + bref[i] +"\t");
            System.out.println("cref[" + i + "]=" + cref[i]);
        }
    } //end of main
} //end of ArrayRefMain class
//㉶--------------------------------------------㉳
/***
C:\javasrc\chap06>javac ArrayRefMain.java
C:\javasrc\chap06>java ArrayRefMain
aref=[I@182f0db
bref=[I@182f0db
cref=[I@182f0db
aref[0]=10      bref[0]=10      cref[0]=10
aref[1]=1       bref[1]=1       cref[1]=1
aref[2]=2       bref[2]=2       cref[2]=2
aref[3]=3       bref[3]=3       cref[3]=3

aref[0]=10      bref[0]=10      cref[0]=10
aref[1]=11      bref[1]=11      cref[1]=11
aref[2]=2       bref[2]=2       cref[2]=2
aref[3]=3       bref[3]=3       cref[3]=3

aref[0]=10      bref[0]=10      cref[0]=10
aref[1]=11      bref[1]=11      cref[1]=11
aref[2]=12      bref[2]=12      cref[2]=12
aref[3]=3       bref[3]=3       cref[3]=3
***/
───────────────────────────────────────ⓑ

예제에서 선언과 동시에 초기화의 기법으로 int[]형의 배열 aref를 생성하고 있습니다.

◈ int[] aref = new int[]{0,1,2,3};

만들어진 aref 배열의 참조값을 bref에, 그리고 다시 bref를 cref에 할당하고 있습니다.

▣ 참조값복사(참조값 할당)
◈ int[] bref = aref;
◈ int[] cref = bref;

기본적으로 배열은 참조의 방법을 따르고 있기 때문에 aref, bref, cref 모두 동일한 참조값을 갖게 됩니다. 즉 메모리 하나에 세 개의 참조변수가 존재하는 것입니다. 위의 참조 방법은 아래의 그림과 같은 구조로 나타낼 수 있습니다. 

배열의 참조값복사【chap06\arrayrefassign.bmp】
 



 
aref, bref, cref 는 모두 하나의 메모리를 참조하고 있기 때문에 어떠한 참조값을 사용하든 하나의 메모리를 상대로 작업하는 것이 됩니다. 이러한 이유에서 배열의 복사라는 부분이 중요하게 다루어지는 것입니다. 위의 그림에서 나타난 참조값의 관계는 다음과 같이 표현될 수 있습니다. 

▣ aref == bref == cref 는 모두 같다.  
◈ aref[0] == bref[0] == cref[0]  모두같다.
◈ aref[1] == bref[1] == cref[1]  모두같다.
◈ aref[2] == bref[2] == cref[2]  모두같다.
◈ aref[3] == bref[3] == cref[3]  모두같다.

▣ 주의할 점
◈ 배열의 이름은 참조변수다. 
◈ 배열끼리 할당할 때 데이터 타입은 같아야 한다. 
◈ 위의 배열들은 데이터 타입이 모두 int[]이다.(aref, bref, cref)

일반적인 클래스 또한 기본적으로 참조값복사의 원리를 사용합니다. int[] 자체가 클래스형이기 때문에 이것은 당연한 논리입니다. 객체의 참조에 대한 간단한 예를 하나 살펴보고 다음으로 넘어가도록 하겠습니다.

『chap06\BabyRefMain.java』
ⓙ───────────────────────────────────────
/**
객체의 참조를 테스트하기 위한 예제
**/
class  Baby{
    private String name;
    public void setName(String name){
        this.name = name;
    }
    public void cry() {
        System.out.println(name + " 가(이) 응애응애");
    }
} //end of Baby class

public class BabyRefMain {
    public static void main(String[] args) {
        Baby b = new Baby();
        System.out.println("Baby b의 참조값 = " + b);
        b.setName("둘리");
        b.cry();
        Baby s = b;
        System.out.println("Baby s의 참조값 = " + s);
        s.setName("아기공룡");
        s.cry();
        b.cry();
    } //end of main
} //end of BabyRefMain class
//㉶--------------------------------------------㉳
/***
C:\javasrc\chap06>javac BabyRefMain.java
C:\javasrc\chap06>java BabyRefMain
Baby b의 참조값 = Baby@192d342
둘리 가(이) 응애응애
Baby s의 참조값 = Baby@192d342
아기공룡 가(이) 응애응애
아기공룡 가(이) 응애응애
***/
───────────────────────────────────────ⓑ

위의 예에서 배열과 같은 방식으로 참조값복사를 하고 있습니다.

▣ 객체의 참조값복사
◈ Baby b = new Baby();
◈ Baby s = b;

객체도 참조를 원칙으로 하고 있기 때문에 b와 s는 같은 메모리를 참조하는 것입니다. 그렇기 때문에 위와 같이 Baby s와 Baby b를 출력해도 같은 참조값이 출력되는 것입니다. 주의하실 것은 객체끼리 할당할 때 데이터 타입의 형이 다르면 참조값복사는 불가능하다는 사실입니다. 상속구조의 업캐스팅과 다운캐스팅 이외에 다른 형의 객체를 할당한다면 무조건 오류가 발생합니다.

▣ 객체의 참조값 할당
◈ 객체는 참조를 원칙으로 한다. 
◈ 객체끼리 할당하면 참조값복사가 된다.
◈ 객체끼리 할당할 때에는 동일한 형에 한해서 이루어진다.



6.3.3 매개변수로서의 배열



매개변수로 배열을 사용하는 경우가 많습니다. 매개변수라 하더라도 참조값복사의 원리는 동일합니다. 매개변수의 인자도 객체변수끼리의 할당이기 때문에 참조값복사를 기본으로 합니다. 여기서는 매개변수라는 측면에서 간단한 예제만을 다루어 보도록 하겠습니다. 

다음과 같은 클래스가 있다고 가정할 때 ArrayParam의 copyArray() 메서드를 통해서 배열을 복사하는 예제입니다.

▣ 배열을 복사하기 위한 클래스를 만들어 보자.
◈ class ArrayParam {
◈        public int[] copyArray(int[] src) {…}
◈        public void copyArray(int[] src, int[] des) {…}
◈ }

위의 클래스를 이용해서 배열을 복사하기 위해서는 다음과 같은 구문을 사용할 것입니다.

▣ 원본 배열
◈ int[] source = new int[]{1,2,3,4,5}; //배열 생성

▣ ArrayParam을 이용한 배열 복사 I
◈ ArrayParam p = new ArrayParam(); //객체 생성
◈ int[] result = p.copyArray(source); //배열을 복사하는 메서드 호출

source 배열을 copyArray() 메서드의 매개변수로 넘겨주었을 때 참조값복사에 의해서 메서드 내에서 source 배열을 사용할 수 있습니다. 이 기법은 하나의 배열을 넘겨주었을 때 메서드 내부에서 메모리를 생성한 후 배열을 복사해서 넘겨주는 방식입니다.

원본 배열과 복사할 배열을 모두 매개변수로 넘겨주는 기법으로 다음과 같은 방식을 사용합니다. 

▣ ArrayParam을 이용한 배열 복사 II
◈ ArrayParam p = new ArrayParam(); //객체 생성
◈ int[] target = new int[source.length];  //복사할 배열 원본
◈ p.copyArray(source, target); //배열을 복사하는 메서드 호출

copyArray()의 매개변수로 원본 배열과 복사할 배열의 참조값을 넘겨주고 메서드를 호출하면 메서드 내부에서 배열의 참조값을 이용해서 배열을 복사하는 방식입니다. 이것을 실제 동작하는 예제로 만들면 다음과 같습니다.

『chap06\ArrayParamMain.java』
ⓙ───────────────────────────────────────
/**
배열의 복사를 직접 구현하는 예
**/
class ArrayParam {
    //배열 복사를 위한 메모리를 메서드 내에서 생성
    public int[] copyArray(int[] src) {
        int[] des = new int[src.length]; //새로운 배열 생성
        for(int i=0; i<src.length; i++)
            des[i] = src[i]; //값복사
        return des;
    }
    //배열 복사를 위한 메모리를 매개변수로 받음
    public void copyArray(int[] src, int[] des) {
        for(int i=0; i<src.length; i++)
            des[i] = src[i]; //값복사
    }
} //end of ArrayPram class

public class ArrayParamMain {
    public static void main(String[] args) {
        int[] source = new int[]{1,2,3,4,5}; //배열 생성
        ArrayParam p = new ArrayParam(); //객체 생성
        //1. copyArray(int[] src) 호출
        int[] result = p.copyArray(source); 
        for(int i=0; i<result.length; i++){
            System.out.println("result["+i+"] : " + result[i]);
        }
        System.out.println();
        //2. copyArray(int[] src, int[] des) 호출
        int[] target = new int[source.length]; 
        p.copyArray(source, target);
        for(int i=0; i<target.length; i++) {
            System.out.println("target["+i+"] : " + target[i]);
        }
    } //end of main
} //end of ArrayParamMain class
//㉶--------------------------------------------㉳
/***
C:\javasrc\chap06>javac ArrayParamMain.java
C:\javasrc\chap06>java ArrayParamMain
result[0] : 1
result[1] : 2
result[2] : 3
result[3] : 4
result[4] : 5

target[0] : 1
target[1] : 2
target[2] : 3
target[3] : 4
target[4] : 5
***/
───────────────────────────────────────ⓑ

ArrayParam 클래스는 배열을 매개변수로 하는 두 개의 메서드를 포함하고 있습니다. 다음은 배열 복사를 위한 오버로딩 메서드입니다.

▣ 배열 복사를 위한 오버로딩 메서드
◈ public int[] copyArray(int[] src) {...}
◈ public void copyArray(int[] src, int[] des) {...}

이 두 메서드는 기능적으로 배열을 복사하는 기능을 가지고 있습니다. 매개변수를 하나 사용하는 것과 두 개를 사용하는 메서드를 오버로딩 기법으로 구현하고 있습니다.

먼저 copyArray(int[] src)는 배열을 src에 넘겨주었을 때, 내부에서 복사할 배열을 생성하고 값복사까지 한 후 리턴하고 있습니다. 즉 원본을 주면 메서드에서 복사본을 만들어 주는 형식입니다. 이 때 src라는 매개변수는 참조값복사에 의해서 전달됩니다.

▣ public int[] copyArray(int[] src)의 예
◈ int[] source = new int[]{1,2,3,4,5};
◈ ArrayParam p = new ArrayParam(); //객체 생성
◈ int[] result = p.copyArray(source); //배열을 복사하는 메서드 호출

이와 같이 메서드를 호출했을 때 source에 해당하는 배열의 참조값이 copyArray()의 매개변수인 src로 참조값복사되는 것입니다.

▣ 배열을 매개변수로 할당할 때 발생하는 참조값복사
◈ int[] src = source;

이렇게 되면 메서드 내부의 src와 main()의 source는 같은 참조값을 가지게 되는 것입니다.

두 번째 copyArray(int[] src, int[] des)는 원본과 복사할 배열을 함께 넣어주면, src에 있는 데이터를 des로 값복사해 주는 방식입니다. copyArray()의 매개변수로 source와 target을 넣어주면 src와 des로 참조값복사가 이루어집니다.

▣ public void copyArray(int[] src, int[] des)의 예
◈ int[] source = new int[]{1,2,3,4,5}; //배열 생성
◈ int[] target = new int[source.length]; 
◈ ArrayParam p = new ArrayParam(); //객체 생성
◈ p.copyArray(source, target); //배열을 복사하는 메서드 호출

두 번째 메서드의 경우에는 두 개의 배열을 생성한 후 copyArray()에 넘겨주고 있습니다. 매개변수를 넘겨줄 때 다음과 같이 참조값복사가 이루어집니다.

▣ 매개변수로 배열이 할당될 때 일어나는 참조값복사
◈ int[] src = source;
◈ int[] des = target;

객체의 참조값만 가지고 있다면 해당 객체를 핸들할 수 있는 것이 자바의 기본이자 가장 중요한 매커니즘입니다. 꼭 기억해 두시기 바랍니다.

▣ 참고
◈ 위의 예제에서 데이터를 핸들할 때 원본만 줄 것인지 아니면 원본과 복사본을 함께 줄 것인지에 대한 프로그래밍 기법은 자주 등장하게 됩니다. 이러한 기법은 스트림을 학습할 때 자주 만날 수 있는 기법이니 디자인적인 측면에서도 한번 검토해 보시기 바랍니다. 

참조는 쉬운데 설명하기가 까다롭군요. 지금까지 1차원 배열의 참조에 대한 사항을 알아보았습니다. 다음으로 2차원 배열에 대해서 학습하도록 하겠습니다.




6.3.4 다차원 배열



이 절의 마지막으로 2차원 배열에 대해서 알아보도록 하겠습니다. 참조라는 관점에서 2차원 배열은 1차원 배열의 확장이기 때문에 기본 원리만 지킨다면 그렇게 어렵지 않게 해결할 수 있습니다. 1차원 배열의 확장이라는 말은 2차원 배열이 배열의 배열이라는 뜻입니다. 즉 2차원 배열을 분해하면 1차원 배열이 된다는 뜻입니다. 먼저 2차원 배열의 핵심사항부터 짚어보고 넘어가기로 하죠.

▣ 2차원 배열의 핵심사항
◈ 2차원 배열의 선언과 초기화
◈ 2차원 배열은 참조의 참조(배열의 배열)

먼저 2차원 배열의 선언부터 살펴보기로 하죠. 2차원 배열은 1차원 배열의 초기화와 같이 하나씩 선언할 수도 있으며 한꺼번에 초기화할 수도 있습니다. 그 방법은 아래와 같습니다.

이차원 배열의 선언과 할당【chap06\array2dimension.bmp】
 



2차원 배열의 첨자는 앞 첨자와 뒤 첨자의 조합을 이용해서 배열의 개수가 정해집니다. 배열의 이름은 참조변수이며, 배열의 요소는 변수입니다. 값을 할당하는 방법은 위의 그림과 같이 선언과 동시에 초기화하는 방법과 선언한 후 하나씩 값을 할당하는 두 가지가 있습니다. 어느 것을 사용하든 값을 할당하는 것은 마찬가지입니다. 

'2차원 배열은 배열의 배열이다'라는 말을 알아보도록 하죠. 하나의 2차원 배열 내에 배열이라고 말할 수 있는 요소는 세 개나 있습니다. 그것은 ar, ar[0], ar[1]입니다. ar은 ar[0]와 ar[1]을 묶어주는 배열이고, ar[0]는 배열의 요소 중 앞 첨자가 0인 변수들의 배열입니다. 그리고 ar[1]은 배열의 요소 중 앞 첨자가 1인 변수들의 배열입니다. 이것에 대한 구조는 아래의 그림과 같습니다.

2차원 배열의 분석【chap06\arrayofarray.bmp】
 



그림에서 보는 바와 같이 3개의 변수를 묶어서 각각 ar[0]와 ar[1]의 배열로 만들고, 다시 배열 ar[0]와 ar[1]을 묶어서 ar이라는 배열로 묶었습니다. 즉 ar은 배열의 배열인 것입니다. 개수를 따지면 ar은 두 개의 원소를 포함하고 있으며, 그리고 ar[0]와 ar[1]은 각각 3개의 원소를 포함하고 있는 것이 됩니다. 그렇다면 ar[0]와 ar[1]은 배열로써 사용할 수 있을까요? 맞습니다. 완벽한 하나의 배열로서 사용할 수 있습니다. ar[0]와 ar[1]은 다음과 같이 원소의 개수를 배열의 방식으로 접근할 수 있습니다.

▣ 2차원 배열
◈ 2차원 배열은 배열의 배열이다.

▣ 배열 ar 내의 배열의 원소
◈ ar.length : 2
◈ ar[0].length : 3 
◈ ar[1].length : 3

이러한 것을 예제로 증명해 보도록 하겠습니다.

『chap06\Array2DimensionMain.java』
ⓙ───────────────────────────────────────
/**
2차원 배열(배열의 배열)을 테스트하는 예제
**/
public class Array2DimensionMain {
    public static void main(String[] args) {
        int[][] src = new int[][]{{100,200,300}, {400,500,600}};
        int[][] tar = {{701,702,703}, {704,705,706}};
        //int[][] src의 정보출력
        System.out.print("src.length:" + src.length + "\t");
        System.out.print("src[0].length:" + src[0].length + "\t");
        System.out.println("src[1].length:" + src[1].length);
        //int[][] tar의 정보출력
        System.out.print("tar.length:" + tar.length + "\t");
        System.out.print("tar[0].length:" + tar[0].length + "\t");
        System.out.println("tar[1].length:" + tar[1].length);
        //2차원 배열의 출력
        for(int i=0; i<src.length; i++)
            for(int j=0; j<src[i].length; j++){
                System.out.print("src[" + i + "][" + j + "]=" + src[i][j] + "\t");
                System.out.print("tar[" + i + "][" + j + "]=" + tar[i][j] + "\n");
            }
            //for문에 블록이 없으면 한 줄에 영향을 준다.
    } //end of main
} //end of Array2DimensionMain class
//㉶--------------------------------------------㉳
/***
C:\javasrc\chap06>javac Array2DimensionMain.java
C:\javasrc\chap06>java Array2DimensionMain
src.length:2    src[0].length:3 src[1].length:3
tar.length:2    tar[0].length:3 tar[1].length:3
src[0][0]=100   tar[0][0]=701
src[0][1]=200   tar[0][1]=702
src[0][2]=300   tar[0][2]=703
src[1][0]=400   tar[1][0]=704
src[1][1]=500   tar[1][1]=705
src[1][2]=600   tar[1][2]=706
***/
───────────────────────────────────────ⓑ

이 예제에서는 2차원 배열을 초기화하는 방법을 보여주고 있습니다. 2차원 배열은 1차원 배열과 초기화 방법이 같지만 블록을 정해주는 것이 다릅니다. 

▣ 2차원 배열의 선언과 초기화를 동시에 하는 방법
◈ int[][] src = new int[][]{{100, 200, 300}, {400,500,600}};
◈ int[][] tar = {{1000, 2000, 3000}, {4000,5000,6000}};

2차원 배열이 '배열의 배열'이라는 증거는 다음의 구문에서 찾아 볼 수 있습니다.

◈ System.out.print("src.length:" + src.length + "\t");
◈ System.out.print("src[0].length:" + src[0].length + "\t");
◈ System.out.println("src[1].length:" + src[1].length);

src는 원래부터 배열이기 때문에 length라는 멤버를 사용할 수 있습니다. src의 length는 2가 됩니다. 그리고 src의 원소인 src[0]와 src[1] 또한 배열이기 때문에 length를 사용할 수 있습니다. src[0]와 src[1]의 length는 각각 3이 됩니다. 위의 예제에서 src의 length에 대한 출력 결과는 다음과 같습니다.

◈ src.length : 2
◈ src[0].length : 3
◈ src[1].length : 3

src는 배열의 배열이기 때문에 src[0]와 src[1]이 요소가 됩니다. 그리고 이 요소들은 그 자체가 배열입니다. src[0]와 src[1]의 개수를 알기 위해서 length 멤버를 사용하면 됩니다. 결국 배열 src는 3개의 배열과 6개의 변수로 이루어져 있는 것이 됩니다.

▣ 배열 src의 구성요소
◈ src: 배열의 배열(1차원 배열) ->겉으로는 2차원 배열이지만 결국에는 1차원 배열이다.
◈ src[0] : 1차원 배열
◈ src[1] : 1차원 배열
◈ src[0][0], src[0][1], src[0][2] : src[0]의 변수들
◈ src[1][0], src[1][1], src[1][2] : src[1]의 변수들

다차원 배열의 원리는 전부 이와 같습니다. 기본 원리만 알고 있다면 아무리 차원이 높은 배열이라 하더라도 쉽게 핸들할 수 있을 것입니다.
저작자 표시 비영리 변경 금지

'JAVA PROGRAMMING > JAVA' 카테고리의 다른 글

7.1 Exception  (0) 2010/02/21
6.4 컬렉션과 맵  (0) 2010/02/21
6.3 배열의 참조  (0) 2010/02/21
6.2 배열  (0) 2010/02/21
6.1 Array, Collection, Map  (0) 2010/02/21
5.5 Downcasting  (0) 2010/02/21
1  ... 53 54 55 56 57 58 59 60 61  ... 159 
BLOG main image
(주)KinTeL 회장 김형기

카테고리

분류 전체보기 (159)
My Name Is KinTeL (3)
농구 인생 (1)
사진 이야기 (13)
미디어 (5)
JAVA PROGRAMMING (105)
C# Programming (2)
FLEX (6)
Database (4)
About Eclipse (1)
참조 - Reference (9)
모든 무료 정보 (2)
좋은글 (2)


Statistics Graph
Total : 73,500
Today : 11
Yesterday : 43

최근에 받은 트랙백