자바 의 clone 방법 인 스 턴 스 상세 설명
clone 은 말 그대로 복사 입 니 다.자바 언어 에서 clone 방법 이 대상 에 의 해 호출 되 기 때문에 대상 을 복사 합 니 다.복사 대상 이란 먼저 원본 대상 과 같은 크기 의 공간 을 분배 하고 이 공간 에서 새로운 대상 을 만들어 야 합 니 다.그렇다면 자바 언어 에 서 는 대상 을 만 들 수 있 는 몇 가지 방법 이 있 습 니까?
1.new 연산 자 를 사용 하여 대상 을 만 듭 니 다.
2.클론 방법 으로 대상 을 복사 합 니 다.
그렇다면 이 두 가지 방식 은 어떤 공통점 과 차이 가 있 을 까?
new 조작 부호 의 본 뜻 은 메모 리 를 분배 하 는 것 이다.프로그램 이 new 연산 자 를 실행 할 때 먼저 new 연산 자 뒤의 종 류 를 보 세 요.종 류 를 알 아야 얼마나 큰 메모리 공간 을 분배 해 야 하 는 지 알 수 있 습 니 다.메모리 가 분 배 된 후에 구조 함 수 를 호출 하여 대상 의 각 도 메 인 을 채 웁 니 다.이 단 계 를 대상 의 초기 화 라 고 합 니 다.구조 방법 이 돌아 온 후에 한 대상 이 생 성 되 었 습 니 다.그의 인용(주소)을 외부 에 발표 할 수 있 고 외부 에서 이 인용 으로 이 대상 을 조작 할 수 있 습 니 다.
한편,클 라 이언 트 는 첫 번 째 단계 에서 new 와 비슷 합 니 다.모두 메모 리 를 분배 하고 클 라 이언 트 방법 을 호출 할 때 분 배 된 메모리 와 원본 대상(즉 클 라 이언 트 방법 을 호출 하 는 대상)이 같 습 니 다.그리고 원래 대상 에 대응 하 는 각 도 메 인 을 사용 하여 새로운 대상 의 도 메 인 을 채 웁 니 다.채 워 진 후에 클 라 이언 트 방법 은 돌아 갑 니 다.새로운 같은 대상 이 생 성 됩 니 다.마찬가지 로 이 새 대상 의 인용 을 외부 에 발표 할 수 있다.
대상 복사 또는 참조 복사
자바 에 서 는 다음 과 같은 코드 가 흔 합 니 다.
Person p = new Person(23, "zhang");
Person p1 = p;
System.out.println(p);
System.out.println(p1);
Person p1=p;실행 후 새로운 대상 을 만 들 었 습 니까?먼저 인쇄 결 과 를 보십시오.
com.pansoft.zhangjg.testclone.Person@2f9ee1ac com.pansoft.zhangjg.testclone.Person@2f9ee1ac
인쇄 된 주소 값 이 같 음 을 알 수 있 습 니 다.주소 가 같 으 니 같은 대상 일 것 입 니 다.p 와 p1 은 인용 일 뿐,그들 은 모두 같은 대상 Person(23,"zhang")을 가리 키 고 있다.이런 현상 을 인용 복제 라 고 할 수 있다.인용 과 대상 의 구분 에 대해 서 는 이전 글 을 참고 할 수 있 습 니 다자바 의 String 은 왜 가 변 적 이지 않 나 요?-String 소스 코드 분석그 중에서 한 절 은 인용 과 대상 의 구분 을 말 했 습 니 다).위의 코드 가 실 행 된 후 메모리 의 상황 은 다음 그림 과 같 습 니 다.다음 코드 는 대상 을 실제로 복제 한 것 입 니 다.
Person p = new Person(23, "zhang");
Person p1 = (Person) p.clone();
System.out.println(p);
System.out.println(p1);
인쇄 결 과 를 통 해 알 수 있 듯 이 두 대상 의 주 소 는 다르다.즉,원래 대상 의 주 소 를 새로운 인용 변수 에 부여 하 는 것 이 아니 라 새로운 대상 을 만 들 었 다.
com.pansoft.zhangjg.testclone.Person@2f9ee1ac com.pansoft.zhangjg.testclone.Person@67f1fba0
메모리 의 상황 은 다음 과 같다.딥 카피 또는 얕 은 카피
위의 예제 코드 에서 Person 에는 name 과 age,name 은 String 형식 이 고 age 는 int 형식 입 니 다.코드 는 매우 간단 합 니 다.아래 와 같 습 니 다.
public class Person implements Cloneable{
private int age ;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public Person() {}
public int getAge() {
return age;
}
public String getName() {
return name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return (Person)super.clone();
}
}
age 는 기본 데이터 형식 이기 때문에 복사 에 대해 의심 할 여지 가 없 으 며 4 바이트 의 전체 수 치 를 복사 하면 됩 니 다.그러나 name 은 String 형식의(비 기본 형식)입 니 다.하나의 인용 일 뿐 진정한 String 대상 을 가리 키 고 있 습 니 다.그러면 복사 하 는 방법 은 두 가지 가 있 습 니 다.원본 대상 의 name 참조 값 을 새 대상 의 name 필드 에 직접 복사 하거나 원래 Person 대상 의 name 이 가리 키 는 문자열 대상 에 따라 같은 문자열 대상 을 만 듭 니 다.이 새 문자열 대상 의 인용 을 새로 복사 한 Person 대상 의 name 필드 에 부여 합 니 다.
이 두 가지 복사 방식 은 각각 얕 은 복사 와 깊 은 복사 라 고 한다.깊 은 복사 와 얕 은 복사 의 원 리 는 다음 그림 과 같다.
다음은 코드 를 통 해 검증 하 겠 습 니 다.
만약 에 두 Person 대상 의 name 주소 값 이 같다 면 두 대상 의 name 이 모두 같은 String 대상,즉 얕 은 복사 대상 을 가리 키 는 것 을 의미 합 니 다.만약 에 두 대상 의 name 주소 값 이 다르다 면 서로 다른 String 대상,즉 Person 대상 을 복사 할 때 name 이 인용 한 String 대상,즉 깊 은 복사 대상 을 가리 키 는 것 을 의미 합 니 다.인증 코드 는 다음 과 같 습 니 다:
Person p = new Person(23, "zhang");
Person p1 = (Person) p.clone();
String result = p.getName() == p1.getName() ? "clone " : "clone ";
System.out.println(result);
인쇄 결과:클론 은 얕 은 카피 입 니 다.
그래서 clone 방법 은 얕 은 복사 입 니 다.프로그램 을 작성 할 때 이 문 제 를 주의해 야 합 니 다.
그러나 우 리 는 Object 의 clone 방법 을 덮어 깊 은 복 사 를 실현 할 수 있다.
현재 클 라 이언 트 대상 을 깊이 복사 하기 위해 서 는 클 라 이언 트 인 터 페 이 스 를 덮어 쓰 고 클 라 이언 트 방법 을 구현 해 야 합 니 다.부모 클래스 의 클 라 이언 트 방법 을 호출 하여 새로운 대상 을 얻 는 것 외 에 도 이 클래스 의 인용 변 수 를 클 라 이언 트 로 만들어 야 합 니 다.Object 의 기본 clone 방법 만 사용 하면 얕 은 복사 입 니 다.다음 코드 로 다시 검증 합 니 다.
static class Body implements Cloneable{
public Head head;
public Body() {}
public Body(Head head) {this.head = head;}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
static class Head /*implements Cloneable*/{
public Face face;
public Head() {}
public Head(Face face){this.face = face;}
}
public static void main(String[] args) throws CloneNotSupportedException {
Body body = new Body(new Head());
Body body1 = (Body) body.clone();
System.out.println("body == body1 : " + (body == body1) );
System.out.println("body.head == body1.head : " + (body.head == body1.head));
}
상기 코드 중 두 가지 주요 유형 이 있 는데 각각 바디 와 페 이 스 이 고 바디 류 에서 하나의 페 이 스 대상 을 조합 했다.바디 대상 을 clone 할 때,그 조합의 페 이 스 대상 은 얕 은 복사 만 한다.인쇄 결 과 는 이 결론 을 검증 할 수 있 습 니 다.
body == body1 : false body.head == body1.head : true
바디 대상 을 clone 할 때 딥 카피 하려 면 바디 의 clone 방법 에서 원본 대상 을 인용 한 Head 대상 도 clone 1 부 를 사용 해 야 한다.
static class Body implements Cloneable{
public Head head;
public Body() {}
public Body(Head head) {this.head = head;}
@Override
protected Object clone() throws CloneNotSupportedException {
Body newBody = (Body) super.clone();
newBody.head = (Head) head.clone();
return newBody;
}
}
static class Head implements Cloneable{
public Face face;
public Head() {}
public Head(Face face){this.face = face;}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Body body = new Body(new Head());
Body body1 = (Body) body.clone();
System.out.println("body == body1 : " + (body == body1) );
System.out.println("body.head == body1.head : " + (body.head == body1.head));
}
인쇄 결과:body == body1 : false body.head == body1.head : false
이 를 통 해 알 수 있 듯 이 body 와 body 1 안의 head 인용 은 서로 다른 Head 대상 을 가리 키 고 있다.즉,clone Body 대상 과 함께 인 용 된 Head 대상 을 복사 하여 깊이 복사 한 것 이다.
진짜 딥 카피 야?
지난 절의 내용 을 통 해 다음 과 같은 결론 을 얻 을 수 있다.만약 에 대상 을 깊이 복사 하려 면 이 대상 은 반드시 Cloneable 인 터 페 이 스 를 실현 하고 clone 방법 을 실현 해 야 한다.또한 clone 방법 내부 에서 이 대상 이 인용 한 다른 대상 도 clone 한 부 를 해 야 한다.그러면 이 인용 대상 도 반드시 Cloneable 인 터 페 이 스 를 실현 하고 clone 방법 을 실현 해 야 한다.
그러면 위의 결론 에 따 르 면 바디 류 는 헤드 류 를 조합 하고 헤드 류 는 페 이 스 류 를 조합 했다.바디 류 를 깊이 복사 하려 면 바디 류 의 클론 방법 에서 헤드 류 도 복사 해 야 한다.그러나 헤드 류 를 복사 할 때 기본 으로 하 는 것 은 얕 은 복사 이다.즉,헤드 에서 조합 한 페 이 스 대상 은 복사 되 지 않 는 다 는 것 이다.인증 코드 는 다음 과 같 습 니 다.
static class Body implements Cloneable{
public Head head;
public Body() {}
public Body(Head head) {this.head = head;}
@Override
protected Object clone() throws CloneNotSupportedException {
Body newBody = (Body) super.clone();
newBody.head = (Head) head.clone();
return newBody;
}
}
static class Head implements Cloneable{
public Face face;
public Head() {}
public Head(Face face){this.face = face;}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
static class Face{}
public static void main(String[] args) throws CloneNotSupportedException {
Body body = new Body(new Head(new Face()));
Body body1 = (Body) body.clone();
System.out.println("body == body1 : " + (body == body1));
System.out.println("body.head == body1.head : " + (body.head == body1.head));
System.out.println("body.head.face == body1.head.face : " + (body.head.face == body1.head.face));
}
인쇄 결과:body == body1 : false body.head == body1.head : false body.head.face == body1.head.face : true
메모리 구 조 는 다음 과 같다.
그렇다면 바디 대상 에 게 는 딥 카피 라 고 할 수 있 을 까?사실 딥 카피 라 고 할 수 있 습 니 다.바디 대상 내 에서 인용 한 다른 대상(현재 Head 만)을 모두 카피 했 기 때 문 입 니 다.즉,두 개의 독립 된 바디 대상 내 헤드 인용 은 독립 된 헤드 대상 두 개 를 가리 키 고 있 기 때 문 입 니 다.그러나 이 는 두 헤드 대상자 에 게 동일 한 페 이 스 상 대 를 가리 키 는 것 으로,이 는 두 바디 대상자 가 여전히 일정한 연관 성 을 갖 고 있 고 완전히 독립 된 것 은 아니 라 는 것 을 보 여 준다.이것 은 마 땅 히 철저 하지 못 한 깊 은 복사 라 고 말 해 야 한다.
어떻게 철저한 딥 복사 를 진행 합 니까
위의 예 에서 어떻게 해야만 두 바디 대상 이 완전히 독립 할 수 있 습 니까?헤드 대상 을 복사 할 때 도 페 이 스 대상 을 1 부 복사 하면 된다.이 는 Face 류 도 Cloneable 인 터 페 이 스 를 실현 하고 clone 방법 을 실현 하 며 Head 대상 의 clone 방법 에서 인용 한 Face 대상 을 복사 해 야 한다.수 정 된 부분 코드 는 다음 과 같 습 니 다.
static class Head implements Cloneable{
public Face face;
public Head() {}
public Head(Face face){this.face = face;}
@Override
protected Object clone() throws CloneNotSupportedException {
//return super.clone();
Head newHead = (Head) super.clone();
newHead.face = (Face) this.face.clone();
return newHead;
}
}
static class Face implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
위의 예 시 를 다시 실행 하면 다음 과 같은 실행 결 과 를 얻 을 수 있 습 니 다.body == body1 : false body.head == body1.head : false body.head.face == body1.head.face : false
이 는 두 바디 가 완전히 독립 되 었 다 는 것 이다.그들 이 간접 적 으로 인용 한 face 대상 은 이미 복사 되 었 다.즉,독립 된 Face 대상 을 인용 한 것 이다.메모리 구성 도 는 다음 과 같 습 니 다.
이에 따라 페 이 스 대상 이 다른 대상,예 를 들 어 Mouth 를 인용 했다 면 처리 되 지 않 았 다 면 Body 대상 은 복사 한 후에 도 1 급 1 급 인용 을 통 해 같은 Mouth 대상 에 인 용 될 것 으로 추정 된다.마찬가지 로 바디 를 인용 체인 에서 완전히 독립 시 키 려 면 마우스 대상 도 명시 적 으로 복사 할 수 밖 에 없다.
이 를 통 해 다음 과 같은 결론 을 얻 을 수 있다.만약 에 한 대상 을 복사 할 때 이 복사 대상 과 소스 대상 이 서로 독립 시 키 려 면 인용 체인 의 모든 등급 대상 이 명시 적 으로 복사 되 어야 한다.
따라서 철저한 딥 복사 본 을 만 드 는 것 은 매우 번 거 로 운 일이 다.특히 인용 관계 가 매우 복잡 한 상황 에서 인용 체인 의 한 단계 에서 제3자 의 대상 을 인용 했다.이 대상 은 clone 방법 을 실현 하지 못 하면 그 후의 모든 인용 대상 은 공유 된다.예 를 들 어 Head 에 인 용 된 Face 클래스 가 제3자 라 이브 러 리 의 클래스 이 고 Cloneable 인 터 페 이 스 를 실현 하지 못 하면 Face 이후 의 모든 대상 이 앞 뒤의 두 바디 대상 에 의 해 공동으로 인 용 됩 니 다.Face 대상 내부 에 Mouth 대상 을 조합 하고 Mouth 대상 내부 에 Tooth 대상 을 조합 했다 고 가정 하면 메모리 구 조 는 다음 과 같다.
마지막 에 쓰다
clone 은 평소 프로젝트 개발 에 자주 사용 되 지 않 을 수 있 지만 깊 은 복사 와 얕 은 복사 로 구분 하면 자바 메모리 구조 와 운영 방식 에 대해 더욱 깊이 알 수 있 습 니 다.철저한 복사 에 대해 서 는 거의 불가능 하 다.그 이 유 는 이미 지난 절 에서 설명 되 었 다.
깊 은 복사 와 철저한 깊 은 복사,불가 변 대상 을 만 들 때 프로그램 에 미묘 한 영향 을 미 칠 수 있 으 며,우리 가 만 든 불가 변 대상 이 정말 불가 변 한 것 인지 아 닌 지 를 결정 할 수 있 습 니 다.clone 의 중요 한 응용 프로그램 도 변 하지 않 는 대상 을 만 드 는 데 사 용 됩 니 다.가 변 적 이지 않 은 대상 을 만 드 는 것 에 대해 서 는 후속 글 에서 설명 할 것 입 니 다.
자바 의 클 라 이언 트 방법 에 대한 자세 한 설명 은 여기까지 입 니 다.자바 의 클 라 이언 트 방법 에 대한 내용 은 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.