[Java] 자바 배열을 복사하는 다양한 방법 (깊은복사, 얕은복사)

    자바에서 객체를 복사하는 유형으로 깊은 복사와 얕은 복사가 있습니다. 깊은 복사의 경우 객체의 실제값을 새로운 객체로 복사하는 것이고 얕은 복사는 단순히 객체의 주소 값만을 복사하는 것입니다. 이 두가지 방식은 각각의 장단점이 있습니다. 먼저 얕은 복사의 경우 여러 객체가 같은 주소를 참조하기 때문에 하나의 값을 변경해버리면 다른 대상의 값 또한 바뀌어 버리는 문제 등이 발생합니다. 하지만 깊은 복사의 경우 실제로 대상이 두개가 생기므로 이러한 문제에서는 자유로울 수 있겠습니다. 반대로 메모리 측면에서 본다면 한 객체로 할 수 있는 일은 하나로 끝내는것이 좋습니다. 쓸데없이 두개 세개가 되면 그야말로 메모리 측면에서 본다면 비효율적이게 됩니다.

     

    이렇듯 얕은 복사로 객체가 복사된다면 실제로는 하나의 주소 값을 가지고 있으므로 하나라고 볼 수 있습니다. 하나의 객체로써 사용이 가능하다면 쓸데없이 객체를 복사하여 사용할 필요는 없지만 이럴 경우 복사한다는 의미보다는 같이 사용한다라는 의미가 됩니다. 그렇기에 대개 객체를 복사한다는 말은 얕은 복사가 아닌 깊은 복사를 의미합니다.

    얕은 복사(Shallow Copy) : 복사된 배열이나 원본배열이 변경될 때 서로 간의 값이 같이 변경됩니다.
    깊은 복사(Deep Copy) : 복사된 배열이나 원본배열이 변경될 때 서로 간의 값은 바뀌지 않습니다.

     

    얕은 복사

    얕은복사

    public class Array_Copy{
        public static void main(String[] args)  {
            int[] a = { 1, 2, 3, 4 };
            int[] b = a;
        }
    }
    

    = 연산자는 주소를 이어준다는 의미입니다. 해당 코드로 a의 배열을 b배열로 = 연산자를 활용하여 대입하면 깊은 복사가 되지 않고 얕은 복사가 됩니다. 그렇기에 b배열의 값을 수정하여도 a배열까지 같이 수정되어버리는 상황이 나옵니다. 이렇게 되면 사실상 배열을 복사하는 의미가 없습니다.

     

    깊은 복사

    깊은복사

    public class Array_Copy{
        public static void main(String[] args)  {
            int[] a = { 1, 2, 3, 4 };
            int[] b = new int[a.length]; 
            for (int i = 0; i < a.length; i++) {
                b[i] = a[i];
            }
        }
    }
    

    상황에 따라 다를수는 있겠지만 제대로 배열을 복사하는 의미를 가지려면 배열의 깊은 복사를 하여야 합니다. 그래야 복사한 배열을 수정하더라도 원본에 배열이 변경되지 않습니다. 위와 같이 for문을 돌려가며 일일이 값을 옮겨도 되지만 자바에서 배열을 복사할 수 있는 여러 가지 메서드를 제공하고 있으니 그것들을 활용하면 배열을 쉽게 복사할 수 있습니다.

     

     배열을 복사하는 여러가지 메서드 

    Object.clone()

    public class Array_Copy{
        public static void main(String[] args)  {
            int[] a = { 1, 2, 3, 4 };
            int[] b = a.clone();
        }
    }
    

    Array.clone()을 사용하면 배열을 쉽게 복사할 수 있습니다. (깊은 복사) 가장 보편적인 방법입니다.

     

    Arrays.copyOf()

    import java.util.Arrays;
    
    public class Array_Copy{
        public static void main(String[] args)  {
            int[] a = { 1, 2, 3, 4 };
            int[] b = Arrays.copyOf(a, a.length);
        }
    }
    

    Arrays클래스는 배열을 조작할 수 있는 메소드를 가진 클래스입니다. 이 클래스 안에 있는 Arrays.copyOf()를 사용하면 배열의 시작점 ~ 원하는 length까지 배열의 깊은 복사를 할 수 있습니다.

     

    Arrays.copyOfRange()

    import java.util.Arrays;
    
    public class Array_Copy{
        public static void main(String[] args)  {
            int[] a = { 1, 2, 3, 4 };
            int[] b = Arrays.copyOfRange(a, 1, 3);
        }
    }
    

    Arrays.copyOf()는 배열의 처음~지정한 length까지 복사하는 메서드였다면 Arrays.copyOfRange() 메서드는 복사할 배열의 시작점도 지정할 수 있습니다.

     

    System.arraycopy()

    public class Array_Copy{
        public static void main(String[] args)  {
            int[] a = { 1, 2, 3, 4 };
            int[] b = new int[a.length];
            System.arraycopy(a, 0, b, 0, a.length);
        }
    }
    

    System.arraycopy() 메서드는 지정된 배열을 대상 배열의 지정된 위치에 복사합니다.

     

     2차원 배열의 깊은 복사 

    1차원 배열의 깊은 복사의 경우 위에서 소개한 메서드를 사용하면 쉽게 복사가 가능합니다. 하지만 2차원 배열의 경우 위의 메서드를 활용해도 깊은 복사가 되지 않습니다.

    2차원 배열 깊은복사

    그 이유는 위와 같은 2차원 배열의 구조 a[x][y]에서 배열을 복사하는 메서드를 사용하게 되면 y좌표를 가리키는 주소 값만 있는 a[x] 부분만 깊은 복사가 되고 값이 있는 a[x][y]는 깊은 복사가 되지 않습니다. 그렇기에 2차원 배열을 복사하기 위해서는 for문을 돌리면서 값이 있는 a[x][y]를 일일이 복사해주어야 합니다.

     

    이중 for문 활용

    public class Array_Copy{
        public static void main(String[] args)  {
            int a[][] = {{1,2,3},{4,5,6,},{7,8,9}};
            int[][] b = new int[a.length][a[0].length];
    	    
            for(int i=0; i<a.length; i++) {
                for(int j=0; j<a[i].length; j++) {
                    b[i][j] = a[i][j];  
                }
            }
        }
    }
    

    2차원 객체 배열의 복사를 할 경우 arraycopy나 clone을 이용해서 복사할 수가 없습니다. 그렇기에 이중 포문을 복사하시려면 이중 for문을 돌면서 값을 일일이 옮겨주셔야 합니다.

     

    System.arraycopy 활용

    public class Array_Copy{
        public static void main(String[] args)  {
            int a[][] = {{1,2,3},{4,5,6,},{7,8,9}};
            int b[][] = new int[a.length][a[0].length];
    	    
            for(int i=0; i<b.length; i++){
                System.arraycopy(a[i], 0, b[i], 0, a[0].length);
            }
        }
    }
    

    이중 for문이 싫으시다면 for문을 돌려 System.arraycopy 메서드를 이용해 2차원 배열을 복사할 수 있습니다. 1차원 배열을 2차원 배열의 row 길이만큼 복사합니다.

    댓글

    Designed by JB FACTORY