머리말
Java Cloning (Clone)은 Java 언어의 기능 중 하나이지만 실제로 사용하는 것은 드 rare니다. 그러나 때로는 복제가 더 편리하고 효율적입니다.
클론의 경우 Java는 몇 가지 제한 사항이 있습니다.
1. 복제 된 클래스는 복제 가능한 인터페이스 자체를 구현하여 Object.clone() 메소드 가이 클래스의 인스턴스를 필드별로 합법적으로 복사 할 수 있음을 나타냅니다. 클로닝 가능한 인터페이스는 실제로 식별 인터페이스이며 인터페이스 방법이 없습니다.
2. 클로닝 가능한 인터페이스를 구현하는 클래스는 공개 방법을 사용하여 Object.clone (보호됩니다)을 무시해야합니다. 이 인터페이스를 구현 한 후 객체를 복제하는 것은 불가능합니다. 복제 방법을 반사적으로 불리더라도 성공할 것이라는 보장은 없습니다.
3. Java.lang.Object 클래스의 클로닝 방법은 다음과 같이 정의됩니다.
보호 된 객체 클론 ()은 ClonenotsupportedException을 던졌습니다
이 개체의 사본을 생성하고 반환합니다. 동일한 패키지에서 볼 수있는 보호 된 방법임을 나타냅니다.
컨벤션에 의해, 반환 된 물체는 super.clone 호출하여 얻어야합니다.
Java의 과제
Java에서는 과제가 매우 일반적으로 사용되며 간단한 과제는 다음과 같습니다.
// 원래 유형 int a = 1; int b = a; // 참조 유형 문자열 [] 주중 = 새 문자열 [5]; 문자열 [] gongzuori = 주중; // 참조 만 복사
위 코드에서.
1. 원래 데이터 유형 인 경우 할당이 전달되는 값이 실제 값입니다.
2. 참조 데이터 유형 인 경우 할당은 객체가 아닌 객체에 대한 참조를 전달합니다.
데이터 유형과 참조 유형의 차이를 이해하면 클론을보다 쉽게 이해할 수 있습니다.
클론
Java에서 클론은 기존 객체를 메모리로 복사하는 프로세스와 동일합니다. Java의 클로닝은 도메인 별 도메인 사본입니다.
Java에서 복제 방법을 지원하려면 먼저 클로닝 가능한 인터페이스를 구현해야합니다 .
복제 가능한 것은 실제로 약간 이상합니다. 우리가 자주 사용하는 인터페이스와 다릅니다. 내부에는 어떤 메소드도 포함되어 있지 않으며 단지 마킹 인터페이스 일뿐입니다.
소스 코드는 다음과 같습니다
공개 인터페이스 클로닝 가능 {}복제 가능한 것에 대해, 무엇에주의를 기울여야하는지
1. 클론을 지원하려면 복제 가능한 인터페이스를 구현해야합니다.
2. 클론 방법이 클로닝 가능한 인터페이스로 호출되지 않으면 ClonenOnsUpportedException이 발생합니다.
그런 다음 복제 방법을 다시 작성하여 공개 액세스 수준으로 수정하십시오.
정적 클래스 클로닝 가능 여기는 클로닝 가능한 {public int count; 공공 아동 아이; @override public Object Clone ()는 clonenotsupportedException {return super.clone (); }}복제 방법을 호출하여 개체를 복사하십시오
클로닝 가능한 IMP1 = 새로운 클로닝 가능 여기 (); imp1.child = new child ( "andy"); try {object obj = imp1.clone (); 클로닝 가능한 야외 imp2 = (클로닝 가능한 촬영) obj; System.out.println ( "main imp2.child.name =" + imp2.child.name);} catch (clonenotsupportedException e) {e.printstacktrace ();}라이트 카피
위 코드에서 구현 된 클론은 실제로 얕은 사본입니다.
얕은 사본에 대해 알아야 할 것
1. 기본 클론 방법을 사용하십시오
2. 원래 데이터 필드의 값 사본 만들기
3. 참조 유형에 대한 참조 만 복사하십시오
4. 빠른 실행 및 고효율
5. 데이터를 100%분리 할 수 없습니다.
6. 객체에 원래 데이터 도메인 또는 불변의 객체 도메인 만 포함 된 경우 얕은 사본을 사용하는 것이 좋습니다.
데이터를 분리 할 수없는 것과 관련 하여이 코드를 사용하여 확인할 수 있습니다.
클로닝 가능한 IMP1 = 새로운 클로닝 가능 여기 (); imp1.child = new child ( "andy"); try {object obj = imp1.clone (); 클로닝 가능한 야외 imp2 = (클로닝 가능한 촬영) obj; imp2.child.name = "bob"; System.out.println ( "main imp1.child.name =" + imp1.child.name);} catch (clonenotsupportedexception e) {e.printstacktrace ();} 위의 코드에서는 IMP1의 클론 방법을 사용하여 CLONE IMP2를 사용한 다음 imp2.child.name bob으로 수정 한 다음 imp1.child.name 인쇄하여 결과를 얻었습니다.
Main Imp1.child.name = Bob
그 이유는 얕은 사본이 데이터를 100% 분리하지 않기 때문입니다. IMP1 및 IMP2는 동일한 하위 객체를 공유하므로 한 수정은 다른 수정에 영향을 미칩니다.
딥 카피
딥 카피는 데이터의 100% 분리 문제를 해결할 수 있습니다. 위의 코드를 수정하십시오.
1. 어린이는 복제 가능한 인터페이스를 구현합니다.
공개 수업 아동은 복제 가능한 {공개 문자열 이름; 공개 아동 (문자열 이름) {this.name = 이름; } @override public String toString () {return "child [name =" + name + "]; } @Override Protected Object Clone ()는 ClonenOntSupportedException {return super.clone (); }}2. 복제 방법을 다시 작성하고 데이터 도메인의 클론 방법을 호출하십시오.
정적 클래스 클로닝 가능 여기는 클로닝 가능한 {public int count; 공공 아동 아이; @override public object clone ()는 clonenotsupportedexception {clonebleimp obj = (clonebleimp) super.clone (); obj.child = (child) child.clone (); 반환 obj; }} imp2.child.name 다시 수정하면 imp1.child.name 의 값에 영향을 미치지 않습니다. IMP1과 IMP2에는 각각 자체 객체가 있기 때문에 데이터가 100% 분리되어 있기 때문입니다.
딥 카피의 일부 기능
1. 상위 클래스 메소드를 호출 할뿐만 아니라 속성의 클론 메소드를 호출하는 클론 메소드를 대체해야합니다.
2. 원래 객체와 복제 된 물체 사이의 데이터 분리가 달성됩니다.
3. 객체에 참조 유형 속성이있는 경우 딥 카피를 사용하는 것이 좋습니다.
4. 딥 카피는 시간이 많이 걸리고 얕은 사본보다 효율적입니다.
클로닝을 사용하는 이유
매우 중요하고 일반적입니다. API는 목록 수집을 제공해야하지만 발신자의 수정이 자체 변경에 영향을 미치기를 원하지 않으므로 데이터 격리의 목적을 달성하기 위해 객체를 복제해야합니다.
클로온은 가능한 한 많이 피해야합니다
1. 일반적으로 인터페이스는 클래스가 고객을 위해 할 수있는 일을 보여주기 위해 구현되며 클로닝 가능은 단지 태그 인터페이스 일 뿐이며 슈퍼 클래스에서 손으로 보호 된 메소드의 동작을 변경합니다. 그것은 인터페이스의 극도로 비정형적인 사용이며 모방 할 가치가 없습니다.
2. 클론 방법 협약과 연약한 클론 방법에 대한 Javadoc 설명은 다음과 같이 약간 모호합니다. Java SE8 컨벤션
복제 방법은 객체의 사본을 생성하고 반환합니다. 사본의 정확한 의미는 객체의 클래스에 따라 다릅니다. 일반적인 의미는 모든 객체 X의 경우 표현식이
x.clone() != x 为true x.clone().getClass() == x.getClass() 도 true를 반환하지만 필요하지 않은 x.clone().equals(x)
위의 두 번째 및 세 번째 표현은 쉽게 거짓을 반환합니다. 따라서 영구적 인 진실을 보장 할 수있는 유일한 것은 표현식 1, 즉 두 객체는 독립 객체입니다.
3. 가변 객체의 최종 도메인. 클로닝 방법에서 가변 객체의 최종 도메인을 복사 해야하는 경우 최종 제한으로 인해 컴파일 및 통과하는 것은 실제로 불가능합니다. 따라서 클로닝을 구현하려면 변이 가능한 객체 도메인의 최종 키워드를 포기하는 것을 고려해야합니다.
4. 스레드 안전 스레드-안전 클래스를 사용하여 클로닝 가능한 인터페이스를 구현하기로 결정한 경우 클론 방법이 동기화되어 있는지 확인해야합니다. 기본 Object.clone 메소드는 동기화되지 않습니다.
일반적으로 Java의 클론 방법은 실제로 완벽하지 않으므로 가능한 한 많이 사용하지 않는 것이 좋습니다. 다음은 몇 가지 대안입니다.
생성자 복사
복사 객체는 사본 생성자를 사용하여 구현할 수도 있습니다.
1. 사본 생성자는 또한 생성자 유형입니다
2. 하나의 매개 변수 만 허용되고 매개 변수 유형은 현재 클래스입니다.
3. 목적은
4. 클론 방법보다 복사 생성자의 장점은 간단하고 구현하기 쉽다는 것입니다.
사본 생성자를 사용한 예제 코드
공공 클래스 카 {휠 휠; 문자열 제조업체; 퍼블릭 카 (휠 휠, 스트링 제조업체) {this.wheel = 휠; this.manufacturer = 제조업체; } // 생성자 공용 차량 (자동차 자동차) {this (CAR.Wheel, CAR.Manufacturer); } public static 클래스 휠 {문자열 브랜드; }}위의 코드는 얕은 사본으로 구현됩니다. 딥 카피를 구현하려면 다음 코드를 참조하십시오.
// CORVERUCTORPUBLIC CAR (CAR CAR) {Wheel Wheel = New Wheel (); 휠 .Brand = car.wheel.brand; wheel = 휠; this.manufacturer = car.manufacturer;}더 편의를 위해 위의 클래스에 정적 메소드를 추가 할 수도 있습니다.
공공 정적 자동차 Newinstance (자동차 자동차) {return 새 차 (자동차);}딥 카피를 얻으려면 직렬화 가능한 사용을 사용하십시오
실제로, 직렬화를 사용하여 객체의 깊은 사본을 달성 할 수 있습니다. 간단한 코드는 다음과 같습니다
공개 클래스 DeepCopyExample Serializable {Private Static Final Long SerialversionUID = 6098694917984051357L; 공공 아동 아이; public deepcopyexample copy () {deepcopyexample copy = null; try {bytearrayoutputstream baos = new BytearRayoutputStream (); ObjectOutputStream OOS = 새로운 ObjectOutputStream (BAOS); oos.writeobject (this); BytearrayinputStream bais = 새로운 BytearrayinputStream (baos.tobytearray ()); ObjectInputStream OIS = New ObjectInputStream (BAIS); copy = (deepcopyexample) ois.readobject (); } catch (ioexception e) {e.printstacktrace (); } catch (classNotFoundException e) {e.printstacktrace (); } 반환 사본; }}그중에서도 아동은 직렬화 가능한 인터페이스를 구현해야합니다
공공 계급 아동은 시리얼이즈 가능 {개인 정적 최종 긴 SerialversionUID = 683212278072711261L; 공개 문자열 이름 = ""; 공개 아동 (문자열 이름) {this.name = 이름; } @override public String toString () {return "child [name =" + name + "]; }}예제 및 테스트 코드를 사용하십시오
DeepCopyExample 예제 = New DeepCopyexample (); 예제 .Child = New Child ( "예"); DeepCopyExample Copy = example.copy (); if (copy! = null) {copy.child.name = "copied"; System.out.println ( "example.child =" + example.child + "; copy.child =" + copy.child);} // 출력 결과 : example.child = child [name = example]; copy.child [name = copied]출력 결과에서 판단하여 사본 객체의 자식 값을 수정하는 것은 예제 객체의 자식 값, 즉 직렬화를 사용하여 객체의 깊은 사본을 달성하지 못합니다.
요약
위의 것은 Java에서 복제의 모든 내용입니다. 이 기사가 모든 사람이 Java를 배우는 데 도움이되기를 바랍니다.