[TIL 26/02/05](Java) 배열(Array)과 Wrapper Class
2026. 2. 5. 17:01
배열(Array)

배열에 대한 내용을 학습했다. 

  • 인덱스(index)
  • 크기 불변
  • 반복문과의 연계성

에 대한 내용을 학습한 뒤 System.arraycopy() 라는 배열 복사 메서드를 알게됐다.

 

이 메서드를 이용한 복사를 얕은 복사라고 하는데, 자바를 공부한 적이 있지만 아예 처음 보는 메서드라 흥미로웠는데 내용을 살펴보면

매개변수를 아래와 같이 5개나 받는데

 

1. 복사할 배열 이름, 2. 복사를 시작할 인덱스, 3. 붙여넣을 배열 이름, 4. 붙여넣기 시작할 인덱스, 5. 복사할 요소의 개수

 

예제로 보면 

 

//System.arraycopy() 예제 1

public class ArrayCopy {

	public static void main(String[] args) {
		int[] array1 = {10, 20, 30, 40, 50};
		int[] array2 = {1, 2, 3, 4, 5};
		
		System.arraycopy(array1, 1, array2, 1, 3);
		
		for(int i : array2) {
			System.out.println(i);
		}

	}

}

//출력 : [1, 20, 30, 40, 5]

 

값이 잘 복사되는 것을 볼 수 있는데 또 다른 신기한 점이 있었다.

 

바로 배열이 기본형 변수가 아닌 객체를 담고 있다면 얕은 복사이기 때문에 객체 자체가 아니라 객체를 가리키는 참조값을 복사한다.

그렇기 때문에 다음 보여줄 예제를 보면 참조값을 복사해서 나오는 결과를 확인할 수 있다.

 

//System.arraycopy() 예제 2

public class ObjectCopy1 {

	public static void main(String[] args) {
		Book[] bookArray1 = new Book[2];
		Book[] bookArray2 = new Book[2];
		
		bookArray1[0] = new Book("신곡", "단테");
		bookArray1[1] = new Book("데미안", "헤르만 헤세");
		
		System.arraycopy(bookArray1, 0, bookArray2, 0, 2);
		
		for(int i=0; i<bookArray2.length; i++){
		bookArray2[i].showBookInfo();
		}
		
		System.out.println("========= ^book2^ =========");
		
		bookArray1[0].setBookName("토지");
		bookArray1[0].setAuthor("박완서");
		
		for(int i=0; i<bookArray1.length; i++){
		bookArray1[i].showBookInfo();
		}
		
		System.out.println("========= ^book1^ =========");
		
		for(int i=0; i<bookArray2.length; i++){
		bookArray2[i].showBookInfo();
		}
		
		System.out.println("========= ^book2^ =========");

	}

}

 

 

객체(Book 클래스의 인스턴스)를 담고 있는 배열 bookArray2는 System.arraycopy() 메서드를 사용해 bookArray1의 참조를 복사했기 때문에 setter를 이용해 bookArray1의 값을 바꾸면 bookArray2의 값도 바뀐 것을 확인할 수 있다.

 

따라서 System.arraycopy()는 객체 배열에 대해서는 얕은 복사를 수행한다는 걸 확인했다.


 

위와 같은 문제를 피하려면 객체를 개별적으로 복사하는 깊은 복사가 필요한데, 깊은 복사는 객체가 가진 내부 필드 값을 각각 복사하는 방식이다.

 

이를 적용했을 때의 결과를 코드로 보면

 

//깊은 복사 예제

public class ObjectCopy2 {

	public static void main(String[] args) {
		Book[] bookArray1 = new Book[2];
		Book[] bookArray2 = new Book[2];
		
		bookArray1[0] = new Book("신곡","단테");
		bookArray1[1] = new Book("데미안", "헤르만 헤세");
		
		bookArray2[0] = new Book(); //객체 직접 생성
		bookArray2[1] = new Book();
		
		for(int i=0; i<bookArray1.length; i++){
		bookArray2[i].setBookName(bookArray1[i].getBookName());
		bookArray2[i].setAuthor(bookArray1[i].getAuthor());
		}
		
		for(int i=0; i<bookArray2.length; i++){
		bookArray2[i].showBookInfo();
		}
		
		System.out.println("========= ^book2^ =========");
		
		bookArray1[0].setBookName("토지");
		bookArray1[0].setAuthor("박완서");
		
		for(int i=0; i<bookArray1.length; i++){
		bookArray1[i].showBookInfo();
		}
		
		System.out.println("========= ^book1^ =========");
		
		for(int i=0; i<bookArray2.length; i++){
		bookArray2[i].showBookInfo();
		}
		
		System.out.println("========= ^book2^ =========");

	}

}

 

 

위와 같이 bookArray2 각 객체에 bookArray1 객체의 필드값을 직접 복사하는 경우(깊은 복사), setter로 bookArray1의 값을 변경해도 bookArray2의 값이 변하지 않은 것을 확인할 수 있다.

 

결과적으로 깊은 복사는 원본 객체의 변경이 복사본에 영향을 주지 않도록 할 때 사용된다.

 

 

 

 

Wrapper Class

자바에선 기본 자료형을 객체처럼 다뤄야 하는 상황이 있다.

예를 들어 컬렉션(List, Map)에는 기본형을 직접 저장할 수 없기 때문에

이를 객체로 감싸는 wrapper class가 필요하다.

 

 

wrapper class는 기본 자료형을 객체로 다루기 위해 사용하는 클래스이며, 포장 객체라고도 부른다.
wrapper class는 불변(immutable) 객체이므로, 값을 변경하려면 새로운 객체를 생성해야 한다.

이러한 특성 때문에 Wrapper Class는 값 변경이 필요한 경우 새로운 객체를 생성하는 방식으로 동작한다.

 

기본 자료형에 각각 대응하는 wrapper class를 표로 표현하면

기본 자료형(primitive type) wrapper class
byte Byte
char Character
int Integer
float Float
double Double
boolean Boolean
long Long
short Short

 

위와 같이 된다.

 

기본 타입 변수를 wrapper class 객체로 포장하는 과정을 박싱(Boxing)이라고 하고,

반대를 언박싱(UnBoxing)이라고 한다.

 

wrapper class의 선언 방식을 Integer 클래스로 예를 들어보면

//wrapper class 선언 예시

Integer i1 = new Integer(8); //비권장
Integer i2 = Integer.valueOf(8);
Integer i3 = Integer.valueOf("8");
Integer i4 = 8  //Auto Boxing

 

위와 같이 선언할 수 있다.

 

그리고 예를 보면 알 수 있듯이 문자열로 저장된 숫자값을 추출하여 정수형 변수에 저장이 가능한데 이런 기능들을 확장하여 살펴보면

 

문자열 => 숫자 (예시는 Integer로)

//문자열 => 숫자 변환 예시

int i1 = Integer.parseInt("8");
Integer i2 = Integer.valueOf("8");

 

 

parseInt()는 기본형 int를 반환하고,
valueOf()는 Wrapper Class 객체(Integer)를 반환한다.

 

 

숫자 => 문자열

//숫자 => 문자열 변환 예시

String s1 = Integer.toString(i1);

 

이렇게 기본형을 사용했을 때보다 숫자-문자열 간의 형변환이 쉬워진다.