답변:
클론이 보호된다는 사실 clone
은 Cloneable
인터페이스 에서 메서드가 선언되지 않았기 때문에 매우 모호 합니다 .
다음과 같이 말할 수 없기 때문에 데이터 사본을 가져 오는 데 방법이 매우 쓸모 없게 만듭니다 .
if(a instanceof Cloneable) {
copy = ((Cloneable) a).clone();
}
의 디자인 Cloneable
은 이제 대체로 실수로 간주 된다고 생각합니다 (아래 인용). 나는 일반적으로 인터페이스의 구현을 할 수 있기를 원 Cloneable
하지만 반드시Cloneable
인터페이스를 만들지는 않습니다 (사용과 유사 함 Serializable
). 이것은 반성 없이는 할 수 없습니다.
ISomething i = ...
if (i instanceof Cloneable) {
//DAMN! I Need to know about ISomethingImpl! Unless...
copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}
Josh Bloch의 효과적인 Java 인용 :
"Cloneable 인터페이스는 객체가 복제를 허용한다고 광고하는 믹스 인 인터페이스로 의도되었습니다. 불행히도이 목적을 달성하지 못합니다 ... 이것은 에뮬레이션 할 인터페이스가 아니라 매우 비정상적인 인터페이스 사용입니다. ... 인터페이스를 구현하여 클래스에 영향을 미치려면 인터페이스와 모든 수퍼 클래스가 상당히 복잡하고 시행 할 수 없으며 대부분 문서화되지 않은 프로토콜을 따라야 합니다. "
Serializable
구현 여부를 결정하는 것은 구현에 달려있다 Serializable
. 나는 이것을 확장했다 Cloneable
– 그것은 인터페이스가 확장해야하는 것이 아니다 – 그러나 인터페이스의 구현은 자유 롭다 Cloneable
. 문제는 인터페이스 유형의 매개 변수가있는 경우 복제 가능 여부를 묻는 것입니다. 하지만 실제로 복제 할 수 없습니다!
Clonable 인터페이스는 클래스가 복제를 지원할 수 있음을 나타내는 마커 일뿐입니다. 이 메서드는 객체에서 호출하지 않아야하기 때문에 보호되며 공용으로 재정의 할 수 있습니다 (그리고 그래야합니다).
Sun에서 :
Object 클래스에서 clone () 메서드는 보호 된 것으로 선언됩니다. Cloneable을 구현하기 만하면 동일한 패키지의 서브 클래스와 멤버 만 객체에서 clone ()을 호출 할 수 있습니다. 모든 패키지의 클래스가 clone () 메서드에 액세스 할 수 있도록하려면 아래 에서처럼이를 재정의하고 public으로 선언해야합니다. (메소드를 재정의 할 때 덜 비공개로 만들 수 있지만 더 비공개로 만들 수는 없습니다. 여기서 Object의 보호 된 clone () 메서드는 공용 메서드로 재정의됩니다.)
Set
clone
현재 클래스에 한정되도록 재정의해야하는 것이기 때문에 보호됩니다. clone
모든 객체를 복제 하는 공용 메서드 를 생성하는 것이 가능할 수 있지만 이는이 를 필요로하는 클래스를 위해 특별히 작성된 메서드만큼 좋지 않을 것입니다.
Clone 메서드는 어떤 개체에서도 직접 사용할 수 없으므로 하위 클래스에 의해 재정의되도록되어 있습니다.
물론 공개 될 수 있고 복제가 불가능할 때 적절한 예외를 던질 수 있지만 오해의 소지가 있다고 생각합니다.
지금 복제가 구현되는 방식은 복제를 사용하려는 이유와 개체를 복제하는 방법에 대해 생각하게합니다.
기본 구현이 모든 필드 (개인용 포함)의 얕은 멤버 별 복사를 수행하고 constructor를 우회 하기 때문에 보호됩니다 . 이것은 객체가 처음에 처리하도록 설계된 것이 아닙니다 (예를 들어, 공유 목록에서 생성 된 객체 인스턴스를 추적하거나 이와 유사한 것).
같은 이유로 기본 구현은 clone()
호출 된 객체가 Cloneable
. 광범위한 결과를 초래할 수있는 잠재적으로 안전하지 않은 작업이므로 클래스 작성자는 명시 적으로 옵트 인해야합니다.
복제 가능의 javadoc에서.
* By convention, classes that implement this interface (cloneable) should override
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.
* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface. Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.
따라서 모든 개체에서 clone을 호출 할 수 있지만 원하는 결과 나 예외가 아닌 대부분의 시간을 제공합니다. 그러나 복제 가능을 구현하는 경우에만 권장됩니다.
IMHO는 다음과 같이 간단합니다.
#clone
복제 할 수없는 개체에서 호출해서는 안되므로 공개되지 않습니다.#clone
Object
올바른 클래스의 얕은 복사본을 얻으려면 Cloneable을 구현 하는 하위 클래스 ob에 의해 호출되어야합니다.하위 클래스에서 호출 할 수 있지만 다른 클래스에서는 호출 할 수없는 메서드의 올바른 범위는 무엇입니까?
그것은이다 protected
.
Cloneable
물론 구현 하는 클래스 는이 메서드를 공개하므로 다른 클래스에서 호출 할 수 있습니다.
Clone () 메소드는 내부적으로 'instance of Cloneable 여부'를 확인합니다. 이것은 Java 팀이 clone () method.clone () 메소드의 부적절한 사용을 제한 할 것이라고 생각할 수있는 방법입니다. 즉, 하위 클래스에서만 액세스됩니다. object는 모든 하위 클래스의 부모 클래스이므로 위의 'instance of Cloneable'확인이 없으면 모든 클래스에서 실제로 Clone () 메서드를 사용할 수 있습니다. 이것이 Java 팀이 clone () 메소드 'Cloneable의 인스턴스입니까'를 확인하여 clone ()의 부적절한 사용을 제한하려고 생각한 이유입니다.
따라서 cloneable을 구현하는 클래스는 Object 클래스의 clone () 메서드를 사용할 수 있습니다.
또한 보호되어 있기 때문에 복제 가능한 인터페이스를 구현하는 하위 클래스에서만 사용할 수 있습니다. 우리가 그것을 공개하고 싶다면,이 메소드는 그것의 자체 구현으로 서브 클래스에 의해 재정의되어야합니다.
네, 제가 만난 것과 같은 문제입니다. 하지만이 코드를 구현하여 해결합니다.
public class Side implements Cloneable {
public Side clone() {
Side side = null;
try {
side = (Side) super.clone();
} catch (CloneNotSupportedException e) {
System.err.println(e);
}
return side;
}
}
누군가가 말했듯이.
글쎄요, 또한 태양 개발자들은 인간 일뿐입니다. 그들은 실제로 복제 메소드를 보호 된 것으로 구현하는 데 큰 실수를 저질렀습니다. ArrayList에서 작동하지 않는 복제 메소드를 구현 한 것과 같은 실수였습니다! 따라서 일반적으로 경험 많은 Java 프로그래머조차도 복제 방법에 대해 훨씬 더 깊은 오해가 있습니다.
그러나 최근에 빌드 방법과 포함 내용에 관계없이 모든 콘텐츠와 함께 모든 개체를 복사하는 빠르고 쉬운 솔루션을 찾았습니다. 여기에서 내 대답을 참조하십시오. Object.clone () 사용시 버그
다시 말하지만, Java JDK 프레임 워크는 훌륭한 사고를 보여줍니다.
복제 가능한 인터페이스에 "public T clone ();"이 없습니다. 메서드는 인스턴스를 복제 할 수 있도록하는 속성 (예 : 직렬화 가능)처럼 작동하기 때문입니다.
이 디자인에는 다음과 같은 이유로 잘못된 것이 없습니다.
Object.clone ()은 사용자 정의 클래스로 원하는 작업을 수행하지 않습니다.
Myclass가 Cloneable을 구현 한 경우 => "public MyClass clone ()"으로 clone ()을 덮어 씁니다.
MyInterface가 Cloneable을 확장하고 MyInterface를 구현하는 일부 MyClass가있는 경우 : 간단히 "public MyInterface clone ();"을 정의하십시오. 인터페이스 및 MyInterface 개체를 사용하는 모든 메서드에서 MyClass 클래스에 관계없이 복제 할 수 있습니다.