깊은 복사와 얕은 복사를 알아보기 전에 우선 객체 배열에 대해 알아본다

 

목차

1. 객체 배열

2. 깊은 복사와 얕은 복사


1. 객체 배열

int[] num=new int[10] 하듯이 객체도 배열을 만들 수 있다.

책 객체 배열을 만들어보자.

Book[] library =new Book[5]이런식으로 만들 수 있다

그렇다면 이렇게 공간을 만들면 Book 인스턴스 5개가 만들어진걸까?

 

아니다. 

 

아래 예제를 보자.

출력결과가 어떻게 될까

package array;
class Book{
	private String bookTitle;
	private String author;
	
	public Book() {}

}

public class BookArray {
	public static void main(String[] args) {
		Book[] library=new Book[5];
	
		
		for(int i=0;i<library.length;i++) {
			
			System.out.println(library[i]);
		}
		
	}

}

아래와 같이 null이 출력되는데 이는 인스턴스가 생성된 것이 아니라 인스턴스 주소가 담길 공간이 5개 생성된 것이다.

 

 

아래와 같이 따로 인스턴스를 또 만들어줘야한다

package array;
class Book{
	private String bookTitle;
	private String author;
	
	public Book() {}
	public Book(String bookTitle,String author) {
		this.bookTitle=bookTitle;
		this.author=author;
	}
}


public class BookArray {
	public static void main(String[] args) {
		Book[] library=new Book[5];
		library[0]=new Book("책제목0","홍길일");
		library[1]=new Book("책제목1","홍길이");
		library[2]=new Book("책제목2","홍길삼");
		library[3]=new Book("책제목3","홍길사");
		library[4]=new Book("책제목4","홍길오");
		
	}

}

 

 

자 이제 본론으로 간다.

 


2. 깊은 복사와 얕은 복사

일단 한 줄 요약하면 

얕은 복사는 인스턴스의 주소가 복사되는 것이고

깊은 복사는 인스턴스의 값이 복사되는 것이다

 

1) 얕은 복사(shallow copy)

아래와 같이 arraycopy메서드를 이용해서 library 배열에 있는 객체 배열을 library1 배열에 복사를 했다.

그런데 아까 객체 배열은 인스턴스 값을 따로 또 생성해줘야하는데 아래 예제에는 인스턴스 값을 따로 생성해주지 않았는데 library1 배열에 똑같이 값이 복사되었다.

어떻게 가능한 것일까?

 

이 경우는 바로 객체의 값이 아니라 주소 값이 복사되었기 때문이다.

주소가 동일하므로 값이 똑같이 출력되는 것이다.

 

그러면 배열을 복사해서 다른 배열로 사용하고 싶으면 어떻게 해야할까?

바로 깊은 복사를 사용하면 된다

package array;
class Book{
	private String bookTitle;
	private String author;
	
	public Book() {}
	public Book(String bookTitle,String author) {
		this.bookTitle=bookTitle;
		this.author=author;
	}
	
	public void showInfo() {
		System.out.println(bookTitle+", "+author);
	}
}

public class BookArray {
	public static void main(String[] args) {
		Book[] library=new Book[5];
		Book[] library1=new Book[5];
		library[0]=new Book("책제목0","홍길일");
		library[1]=new Book("책제목1","홍길이");
		library[2]=new Book("책제목2","홍길삼");
		library[3]=new Book("책제목3","홍길사");
		library[4]=new Book("책제목4","홍길오");
		
		System.arraycopy(library, 0, library1, 0, 5);
			
		for(int i=0;i<library.length;i++) {
			
			library1[i].showInfo();
		}
		
	}

}

 

출력결과

 

2) 깊은 복사

반복문을 사용하든 System.arraycopy()메서드를 사용하든 객체 배열을 복사하면 항상 인스턴스 주소가 복사되므로 따로 관리 하고 싶다면 깊은 복사를 사용해야한다

 

아래 예문을 보자

package array;
class Book{
	private String bookTitle;
	private String author;
	
	public Book() {}
	public Book(String bookTitle,String author) {
		this.bookTitle=bookTitle;
		this.author=author;
	}
	
	
	
	public String getBookTitle() {
		return bookTitle;
	}
	public void setBookTitle(String bookTitle) {
		this.bookTitle = bookTitle;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	public void showInfo() {
		System.out.println(bookTitle+", "+author);
	}
}

public class BookArray {
	public static void main(String[] args) {
		Book[] library=new Book[2];
		Book[] library1=new Book[2];
		library[0]=new Book("책제목0","홍길일");
		library[1]=new Book("책제목1","홍길이");
		
		library1[0]=new Book();
		library1[1]=new Book();
		
		
		for(int i=0;i<library.length;i++) {
			library1[i].setBookTitle(library[i].getBookTitle());
			library1[i].setAuthor(library[i].getAuthor());
		}
		library[0].setBookTitle("책제목3");
		
		for(int i=0;i<library.length;i++) {
			library[i].showInfo();
		}
		
          System.out.println("---------");
          
		for(int i=0;i<library.length;i++) {
			library1[i].showInfo();
		}
		
	}

}

아래와 같이 결과값이 분리되는 것을 볼 수 있다

 

 

출처 : Do it! 자바 프로그래밍 입문-박은종

아래의 첫번째 예시를 보자.

public 접근 제어자를 사용해서 언제든지 멤버 변수의 값이 바뀌도록 했다.

package hiding;

public class Student {
	public int studentID;
	public String studentName;
	public int grade;
	public String address;

}
package hiding;

public class StudentTest {

	public static void main(String[] args) {
		Student student = new Student();
		student.studentName="홍길동";
		System.out.println(student.studentName);

	}

}

 

 

그리고 두번째 예시를 보자.

getter, setter 함수를 이용해 private 멤버변수를 접근하도록 했다.

package hiding;

public class Student {
	public int studentID;
	private String studentName;
	public int grade;
	public String address;
	
	public String getStudentName() {
		return studentName;
	}
	public void setStudentName(String studentName) {
		this.studentName = studentName;
	}

}
package hiding;

public class StudentTest {

	public static void main(String[] args) {
		Student student = new Student();
		//student.studentName="홍길동";
		student.setStudentName("홍길동");
		System.out.println(student.getStudentName());

	}

}

 

 

접근 제어자를 private으로 선언하면 외부 클래스에서 사용할 수 없다.

그리고 위 1, 2예시 모두 결국엔 변수를 사용할 수 있다.

그렇다면 굳이 왜 접근제어자를 private으로 써서 귀찮게 메서드를 만들어 사용하는게 바람직한걸까?

 

 

다음 예제를 보면서 알아보자.

학생수가 32명있어서 학번을 1부터 32번까지 할당하는데 누군가의 실수로 학번이 33번이라고 입력된다고 해보자.

메서드에 조건문을 달아주면 오류가 나더라도 그 값이 해당 변수에 대입되지 않아 정보의 오류를 막을 수 있다

package hiding;

public class Student {
	private int studentID;
	public String studentName;
	public int grade;
	public String address;
	
	
	public int getStudentID() {
		return studentID;
	}
	public void setStudentID(int studentID) {
		if(studentID >32) {
			System.out.println("오류, 다시 입력하시오");
		}else {
		this.studentID = studentID;
	}
 }

}
package hiding;

public class StudentTest {

	public static void main(String[] args) {
		Student student = new Student();
		
		student.setStudentID(33);
		

	}

}

 

이치럼 클래스 내부에 사용할 변수나 메서드는 private으로 선언해서 외부에서 접근하지 못하도록 하는 것을 정보 은닉이라고 한다

 

 

출처 : Do it! 자바 프로그래밍 입문 - 박은종

 

이클립스(Eclipse) 한글 깨짐 - "UTF-8" 인코딩 설정 :: 컴퓨터가 할 일을 사람이 하지말자 (tistory.com)

[Error:Eclipse] 한글깨짐 해결법(UTF-8로 변경해도 해결되지 않을경우) (tistory.com)

이클립스 콘솔 한글깨짐 해결 방법 (tistory.com)

 

위링크보고 다 해봤는데 안됐습니다. 

저는 아래 방법을 사용해서 해결했습니다.

 

1) Run->Run configurations

 

 

 

2) Common 

 

 

3) Encoding에서 Use system encoding(x-windows-949) 클릭

이러니 해결됐습니다

+ Recent posts