본문 바로가기
개발관련

자바 꽉자바! : (2)배열의 복사에 대해 알아보자!

by 수바니 2023. 9. 21.

오늘은 배열의 복사에 대해서 공부해볼거에요 !

 

배열이란? 하나의 공간에 여러개의 값을 담을 수 있는 개념 입니다.

배열의 기본적인것이 더 궁금하다면 이전 게시글을 확인해주세요 !

 

배열의 복사는 두가지로 나뉩니다.

1. 얕은복사

2. 깊은복사

 

얕은복사 : 배열의 주소값을 복사

깊은복사 : 배열의 실제값을 복사

주소값을 복사하는것이 무슨말인가 ?? 한다면 이전 게시글을 봐주세요 !

 

얕은복사의 예시

	public void method1() {
		int[] origin = {1,2,3,4,5};
		
		//for문으로 출력 1 2 3 4 5
		System.out.println("== 원본 배열 출력 ==");
		for(int i=0; i<origin.length; i++ ) {
			System.out.print(origin[i]+ " ");
		}
		System.out.println();
		
		// 단순하게 origin을 다시 대입시킨 copy 배열
		int[] copy = origin;
		System.out.println("== 복사본 배열 출력 ==");
		for(int i=0; i<copy.length; i++) {
			System.out.print(copy[i] + " ");
		}
		System.out.println();
		
		copy[2] = 99;
		
		System.out.println("----- 복사본 배열 값 변경 후 -----");
		
		System.out.println("== 원본 배열 출력 ==");
		for(int i =0; i<origin.length; i++) {
			System.out.print(origin[i] + " ");
		}
		System.out.println();
		System.out.println("== 복사본 배열 출력 ==");
		for(int i =0; i<copy.length; i++) {
			System.out.print(copy[i] + " ");
		}
		System.out.println();

		System.out.println("origin 주소값 : " + origin.hashCode());
		System.out.println("copy 주소값 : " + copy.hashCode());
	}

콘솔창을 확인합니다.

copy만을 가지고 수정을 해도 원본까지 변경되어있습니다.

그 이유는 origin과 copy가 같은곳을 참조하고 있기 때문입니다. == 주소값이 같다.

== 여러 객체가 같은주소를 참조한다.

따라서 얕은복사라고 함은 주소값을 복사하는것입니다.

얕은복사로 객체가 복사된다면 실제로는 하나의 주소 값을 가지고 있으므로 하나라고 볼 수 있습니다.

하나의 객체로써 사용이 가능하다면 쓸데없이 객체를 복사하여 사용할 필요는 없겠지만, 이럴경우에 우리가 생각하는 복사한다는 개념이 아니라고 생각하면됩니다. 우리가 생각하는 복사는 깊은 복사라고 생각하면 되겠습니다!

 

얕은복사의 문제를 해결하기 위해 깊은복사를 배워볼게요!

깊은복사의 예시

// 얕은복사의 문제를 해결하기 위해서 깊은복사
	public void method2() {
		// 1. for문을 활용한 방법
		// 새로운 배열을 생성한 후 반복문을 활용해서 원본배열의 값들을 새로이 만든 배열에 대입하는 방법
		
		int[] origin = {1,2,3,4,5}; // 원본배열
		
		// int[] copy = origin; // 얕은복사 : 주소값 대입
		int[] copy = new int[5];
		
		for(int i=0;i<copy.length;i++) {
			copy[i] = origin[i];
			
		}
		System.out.println("== 원본 배열 출력 ==");
		for(int i=0; i<origin.length; i++) {
			System.out.print(origin[i] + " ");
		}
		System.out.println();
		
		System.out.println("== 복사본 배열 출력 ==");
		for(int i =0; i<copy.length; i++) {
			System.out.print(copy[i] + " ");
		}
		System.out.println("\n");
		
		//copy 배열 수정해보기
		copy[2] = 99;
		System.out.println("\n----- copy 수정후 -----");
		System.out.println("== 원본 배열 출력 ==");
		for(int i =0; i<origin.length; i++) {
			System.out.print(origin[i]+" ");
		}
		System.out.println();
		
		System.out.println("== 복사본 배열 출력 ==");
		for(int i =0; i<copy.length; i++) {
			System.out.print(copy[i] +" ");
		}
		System.out.println();
		
		System.out.println("origin의 주소값 : " + origin.hashCode()); // 깊은복사이므로 주소값이 서로 다르다.
		System.out.println("copy의 주소값 : " + copy.hashCode()); // 깊은복사이므로 주소값이 서로 다르다.
	}

콘솔창을 확인합니다.

얕은복사는 주소값만 대입되어 수정할시에 원본배열과 수정배열도 수정됩니다.

깊은복사는 Heap영역에 새로운 공간이 생성되어 주소값도 달라집니다.

== 원본객체와 복사본 객체는 메모리에서 서로 다른 위치에 있는 배열을 할당하고 있기 때문에 서로의 변화를 영향을 받지 않습니다.

우리가 흔히생각하는 복사라는 개념을 배열에 적용하게 된다면 깊은복사가 되는것입니다.

 

깊은복사 예시 1

arraycopy()메소드 이용하기 (System 클래스에서 제공)

public void method3() {
		// 새로운 배열 생성 후 System이라는 클래스에서의 arraycopy() 메소드를 이용한 복사
		
		int[] origin = {1,2,3,4,5};
		int[] copy = new int[10]; // 넉넉하게 크게 생성 / 0~9 인덱스까지 0이 다 담겨있을 것!!
		
		//System.arraycopy(원본배열명, 복사시작할 인덱스, 복사본배열명, 복사본 배열의 복사될 시작인덱스, 복사할갯수)
		
		//System.arraycopy(origin, 0, copy, 2, 5);
		//System.arraycopy(origin, 0, copy, 0, 5);
		System.arraycopy(origin, 1, copy, 3, 3);
		
		for(int i=0; i<copy.length; i++) {
			System.out.print(copy[i]+ " ");
		}
		System.out.println();
		System.out.println("Origin의 주소값 : " + origin.hashCode());
		System.out.println("copy의 주소값 : " + copy.hashCode());
		
	}

콘솔창 확인

주소값이 다른것을 볼 수 있다. 깊은복사라는 의미.

1. 각자 다른 배열을 참조한다.

2. 배열 수정시 서로에게 영향을 주지 않는다.

 

깊은복사 예시 2

copyOf()메소드 이용하기 (Arrays 클래스에서 제공)

public void method4() { 
		int[] origin = {1,2,3,4,5};
		
		// 복사본 배열 = Arrays.copyOf(원본배열명, 복사할길이);
		//int[] copy = Arrays.copyOf(origin, 5); // Heap영역에 공간도 만들어주고, 주소값도 달라진다.
		//int[] copy = Arrays.copyOf(origin, 3); // 복사할길이 = array의 크기
		int[] copy = Arrays.copyOf(origin, 10);
		
		for(int i=0; i<copy.length; i++) {
			System.out.print(copy[i]+ " ");
		}
		System.out.println();
		
		System.out.println("Origin의 주소값 : " + origin.hashCode());
		System.out.println("copy의 주소값 : " + copy.hashCode());
		
	}

콘솔창 확인

Arrays 클래스에서 제공하는 copyOf() 메소드를 사용하여 배열복사를 해보았다.

 Arrays.copyOf() 메소드

1. 내가 제시한 길이 만큼 복사본 배열 크기 할당

2. 내가 제시한 길이가 원본배열의 크기보다 클 경우 기존의 배열에 있는 값은 다 복사 나머지는 0으로 채운다.

3. 내가 제시한 길이가 원본배열의 크기보다 작을 경우 기존의 배열에 있는 값을 내가 제시한 길이만큼만 복사한다.

 

깊은복사 예시 3

clone()메소드 이용하기 (Object 클래스에서 제공)

public void method5() {
		int[] origin = {1,2,3,4,5};
		// 복사본배열 = 원본배열.clone();
		int[] copy = origin.clone();
		for(int i=0; i<copy.length; i++) {
			System.out.print(copy[i]+" ");
		}
		System.out.println();
		System.out.println("origin의 주소값 : " + origin.hashCode());
		System.out.println("copy의 주소값 : " + copy.hashCode());
	}

콘솔창 확인

clone() 메소드를 이용한 복사

1. 인덱스 지정불가

2. 크기지정 별도로 못합니다.