Programing Language/Java

[Java] 자바 배열의 복사(Arrays Copy)

vinedpillar 2022. 6. 20. 23:07

배열의 복사

  • 배열은 한번 생성하면 크기의 변경이 불가능합니다.

  • 때문에 프로그램 중간에 배열의 크기가 변경되어야 한다면, 더 큰 배열을 생성한 후 복사하는 방법을 사용해야 합니다.

  • 배열은 내부에 저장되는 자료형이 기본 타입인가, 참조 타입인가에 따라서 저장이 다르게 되기 때문에 복사에서도 이를 유의해야 합니다.

  • 배열을 복사하는 방법은 크게 두 가지 방법으로 나뉩니다.
    • 얕은 복사: 실제 배열의 데이터값이 저장된 값의 주소를 복사하여 활용
    • 깊은 복사: 복사한 배열의 데이터값을 완전히 다른 객체에 새로 생성하여 활용 

 

 

 

 

얕은 복사(shallow copy)

  • 얕은 복사를 할 경우 데이터의 주소값을 복사하기 때문에 실제로 힙메모리에 저장되는 데이터는 동일하게 활용합니다.

  • 다른 배열을 선언한 후 그냥 다른 배열의 값에 직접 대입하는 방법을 사용하연 얕은 복사가 됩니다.

  • 이 경우 실제 메모리에 저장된 데이터의 값이 바뀌면 복사된 배열의 데이터값도 변경됩니다.
배열 얕은 복사 예시

// arr1의 배열 값을 새로운 배열에 그대로 대입
int[] arr1 = {1, 2, 3, 4};
int[] arr2 = arr1;

// 내부 값 변경 시 복사된 배열의 값 확인
arr1[3] = 5;

// arr1만 값을 바꿨지만 arr2도 값이 바뀌게 됨
for(int i = 0; i < arr1.length; i++) {
	System.out.print(arr1[i] + ", ");
    // 1, 2, 3, 5 출력
}

System.out.println("");

for(int i = 0; i < arr2.length; i++) {
	System.out.print(arr2[i] + ", ");
    // 1, 2, 3, 5 출력
}

 

 

 

깊은 복사(deep copy)

  • 깊은 복사는 배열의 데이터 주소값이 아닌 실제 값을 복사하는 방법입니다.

  • 깊은 복사를 하기 위해서는 복사할 배열을 새로 생성 후에 값을 직접 넣는 방식으로 복사합니다.

  • 이 경우 배열을 복사해도 원본 배열과 복사된 배열의 데이터가 서로 다른 메모리 주소를 가지게 됩니다.

  • 따라서 원본 배열의 실제 데이터 값을 변경하더라도 복사한 배열의 데이터는 변경되지 않습니다.
배열 깊은 복사 예시

// arr1의 배열 값을 새로운 배열에 그대로 대입
int[] arr1 = {1, 2, 3, 4};
int[] arr2 = new int[arr1.length];

// 새로운 배열 생성 후 내부 값을 직접 대입
for(int i = 0; i < arr2.length; i++) {
	arr2[i] = arr1[i];
}

// 내부 값 변경 시 복사된 배열의 값 확인
arr1[3] = 5;

// arr1만 값을 바꿨지만 arr2의 값은 바뀌지 않음
for(int i = 0; i < arr1.length; i++) {
	System.out.print(arr1[i] + ", ");
    // 1, 2, 3, 5 출력
}

System.out.println("");

for(int i = 0; i < arr2.length; i++) {
	System.out.print(arr2[i] + ", ");
    // 1, 2, 3, 4 출력
}

 

 

 

 

참조 타입의 배열일 경우의 복사

  • 참조 타입 값으로 이루어진 경우 for문을 이용하여 값을 넣어도 주소만 복사되기 때문에 얕은 복사가 됩니다.

  • 참조 타입 값을 가진 배열을 깊게 복사하기 위해서는 각 배열에 직접 객체를 만든 후에 값을 복사해야 합니다.
참조 타입 배열의 깊은 복사 예시

// 동작을 확인하는 메인 메서드
public class refernceTypeArrayExample {
	public static void main(String[] args) {
    	Book[] books1 = new Book[3];
        Book[] books2 = new Book[books1.length];
        Book[] books3 = new Book[books1.length];
        
        // books1의 배열 삽입
        Books1[0] = new Book("책1", "저자1");
        Books1[1] = new Book("책2", "저자2");  
        Books1[2] = new Book("책3", "저자3");
        
        // books1의 객체를 books2에 얕게 복사
        for(int i = 0; i < books1.length; i++) {
            books2[i] = books1[i];
        }
        
        // books1의 객체 정보 변경
        books1[0].setBookName("책4");
        books1[0].setAuthor("저자4");
        
        // books1에서 바뀐 값이 books2에 적용되어있음 
        // 책4, 저자4 출력
        books2[0].checkBookInfo();
        
        
        // books1의 객체를 books3에 깊게 복사
        books3[0] = new Book();
        books3[1] = new Book();
        books3[2] = new Book();
        
        // 새로 생성한 books3의 객체에 books1의 값을 복사
        for(int i = 0; i < books1.length; i++) {
            books2[i].setBookName(books1[i].getBookName());
            books2[i].setAuthor(books1[i].getAuthor());
        }
        
        // books1의 객체 정보 변경
        books1[1].setBookName("책5");
        books1[1].setAuthor("저자5");
        
        // books1의 변경 사항이 books3에 적용되지 않음을 확인
        // 책2, 저자2 출력
        books3[1].checkBookInfo();        
    }
}   
    
// 클래스 선언 영역
// 책의 제목과 저자 이름을 저장하고, 이를 수정 할 수 있는 클래스 정의
public class Book {
    private String bookName;
    private String author;
    
    public Book() {
    
    }
    
    public Book(String bookName, String author) {
    	this.bookName = bookName;
        this.author = author;
    }
    
    public void getBookName() {
    	return bookName;
    }
    
    public setBookName(String bookName) {
    	this.bookName = bookName;
    }
    
    public void getAuthor() {
    	return author;
    }
    
    public setAuthor(String author) {
    	this.author = author;
    }
    
    public checkBookInfo() {
    	System.out.println(bookName + ", " + author);
    }
}

 

 

 

 

배열 복사 메서드

  • 자바에서 제공하는 기본 라이브러리(미리 구현해둔 기능들)의 메서드를 활용하면 배열을 간단하게 복사할 수 있습니다.
    (메서드란 특정 매개변수를 이용하여 특정 값을 반환받는 함수의 일종)

  • Object.clone(): 자바의 Object 클래스에서 제공하는 clone() 메서드를 활용
Object.clone() 메서드 사용 예시

// 메서드 사용 법
복사할 배열.clone();

// 메서드 사용 예시
int[] intarr1 = {1, 3, 5, 7};
int[] intarr2 = intarr1.clone;

// 복사 결과 확인
for(int i = 0; i < intarr1.length; i++) {
	System.out.print(intarr1[i] + ", ");
    // 1, 3, 5, 7, 출력
}

System.out.println("");

for(int i = 0; i < intarr2.length; i++) {
	System.out.print(intarr2[i] + ", ");
    // 1, 3, 5, 7, 출력
}

 

  • Arrays.copyOf(), Arrays.copyOfRange(): Arrays 클래스에서 제공하는 copyOf(), copyOfRange() 메서드를 활용
Arrays.copyOf() 메서드 사용 예시

// Arrays.copyOf() 메서드 사용 법
자료형[] 변수명 = Arrays.copyOf(복사할 배열, 복사할 길이) 

// Arrays.copyOf() 메서드 사용 예시
int[] intarr1 = {1, 3, 5, 7};
int[] intarr2 = Arrays.copyOf(intarr1, 3);


// Arrays.copyOfRange() 메서드 사용 법
자료형[] 변수명 = Arrays.copyOf(복사할 배열, 복사 시작 인덱스, 복사할 길이) 

// Arrays.copyOf() 메서드 사용 예시
int[] intarr1 = {1, 3, 5, 7};
int[] intarr2 = Arrays.copyOf(intarr1, 0, 2);

 

  • System.arraycopy: 자바의 System 클래스에서 제공하는 arraycopy() 메서드를 활용
System.arraycopy() 메서드 사용 예시

// System.arraycopy() 메서드 사용 법
System.arraycopy(복사할 배열, 복사할 배열의 시작 인덱스, 붙여넣기할 배열 이름, 붙여넣을 지점의 인덱스, 복사할 개수)

// System.arraycopy() 메서드 사용 예시
int[] intarr1 = {1, 3, 5, 7};
int[] intarr2 = new int[intarr1.length];

// intarr1의 배열에서 0번째 인덱스부터 intarr1의 길이까지 복사하여 intarr2의 0번째 인덱스부터 채워넣게 됨 
System.arraycopy(intarr1, 0, intarr2, 0, intarr1.length);