clone () 메서드가 java.lang.Object에서 보호되는 이유는 무엇입니까?


112

clone()에서 보호 되는 것으로 정의 된 구체적인 이유는 무엇입니까 java.lang.Object?

답변:


107

클론이 보호된다는 사실 cloneCloneable인터페이스 에서 메서드가 선언되지 않았기 때문에 매우 모호 합니다 .

다음과 같이 말할 수 없기 때문에 데이터 사본을 가져 오는 데 방법이 매우 쓸모 없게 만듭니다 .

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 인터페이스는 객체가 복제를 허용한다고 광고하는 믹스 인 인터페이스로 의도되었습니다. 불행히도이 목적을 달성하지 못합니다 ... 이것은 에뮬레이션 할 인터페이스가 아니라 매우 비정상적인 인터페이스 사용입니다. ... 인터페이스를 구현하여 클래스에 영향을 미치려면 인터페이스와 모든 수퍼 클래스가 상당히 복잡하고 시행 할 수 없으며 대부분 문서화되지 않은 프로토콜을 따라야 합니다. "


2
객체가 Cloneable이 아니면 Object의 clone ()은 CloneNotSupportedException을 발생시킵니다. 따라서 super.clone ()을 호출 할 경우 Cloneable이 필요합니다 (Object.clone ()이 호출 됨). Serializable을 구현하지 않고 객체를 직렬화하는 방법을 알 수 없습니다.
Steve Kuo

1
"Cloneable의 디자인은 이제 대체로 실수로 간주됩니다." [인용 필요]
Kevin Panko

죄송합니다. 그런 뜻이 아닙니다. 나는 단지 "좋은"디자인이 인터페이스를 확장하는 것이 아니라는 것을 암시하고 있었다 . Serializable구현 여부를 결정하는 것은 구현에 달려있다 Serializable. 나는 이것을 확장했다 Cloneable– 그것은 인터페이스가 확장해야하는 것이 아니다 – 그러나 인터페이스의 구현은 자유 롭다 Cloneable. 문제는 인터페이스 유형의 매개 변수가있는 경우 복제 가능 여부를 묻는 것입니다. 하지만 실제로 복제 할 수 없습니다!
oxbow_lakes

6
@Kevin - Josh Bloch의 효과적인 Java pp45. "Cloneable 인터페이스는 그들이 복제를 허용하는 것을 광고하는 객체의 믹스 인 인터페이스로 구성되었다 불행히도이 목적을 제공하지 못한다."
oxbow_lakes

또한 같은 페이지에서 : "이것은 에뮬레이션 할 인터페이스가 아니라 매우 이례적인 인터페이스 사용입니다.""인터페이스를 구현하여 클래스에 영향을 미치려면 인터페이스와 모든 수퍼 클래스가 상당히 복잡한 방식을 따라야합니다 . 집행 크게 문서화되지 않은 프로토콜 "
oxbow_lakes

30

Clonable 인터페이스는 클래스가 복제를 지원할 수 있음을 나타내는 마커 일뿐입니다. 이 메서드는 객체에서 호출하지 않아야하기 때문에 보호되며 공용으로 재정의 할 수 있습니다 (그리고 그래야합니다).

Sun에서 :

Object 클래스에서 clone () 메서드는 보호 된 것으로 선언됩니다. Cloneable을 구현하기 만하면 동일한 패키지의 서브 클래스와 멤버 만 객체에서 clone ()을 호출 할 수 있습니다. 모든 패키지의 클래스가 clone () 메서드에 액세스 할 수 있도록하려면 아래 에서처럼이를 재정의하고 public으로 선언해야합니다. (메소드를 재정의 할 때 덜 비공개로 만들 수 있지만 더 비공개로 만들 수는 없습니다. 여기서 Object의 보호 된 clone () 메서드는 공용 메서드로 재정의됩니다.)


어느, 괜찮 당신이 혼합으로 인터페이스를 가져올 때까지 시도 및 알 수없는 구현이 복제를 시도 -Set
oxbow_lakes

@oxbow_lakes :하지만 세트 어쩌면 일부 구현이 복제 가능하지 않습니다
newacct

3
Clonable 인터페이스를 구현하지 않는 것은 복제 할 수 없습니다. 이것은 Serializable 인터페이스와 매우 유사합니다. "이 클래스는 적절하게 복제 가능합니다."라는 마커입니다. 그건 그렇고, 잘 작동하는 직렬화를 통해 클래스를 복제하는 방법이 있습니다. Google에서 "자바 직렬화 복제"와 같은 것을 사용하면 객체의 깊은 복사본을 얻을 수있는 몇 가지 방법을 찾을 수 있습니다.
Bill K

4
Cloneable 인터페이스를 구현하지 않는 것은 복제 할 수 없지만, Cloneable 인터페이스를 구현한다고해서 복제 할 수 있다는 의미는 아닙니다.
Michael Myers

1
@BuckCherry toString에는 기본 구현이 있으며, 호출하면 좋은 일이 일어나고 문자열이 반환됩니다. equals에는 기본 구현이 있습니다 (==와 동일). 클론은 기본 구현을 가질 수 없습니다. 구현되지 않은 객체에 대해 clone을 호출하면 적절한 동작을 얻지 못합니다. 복제는 복잡하고 실제로 자동으로 수행 될 수 없으므로 (기본 생성자가없는 일부 개체는 일반적으로 복제가 불가능할 수 있음) 기본적으로 조금 더 안전합니다. 그러나 Object에 넣는 것은 필요하지 않았을 수도 있다고 생각합니다.
Bill K

7

clone현재 클래스에 한정되도록 재정의해야하는 것이기 때문에 보호됩니다. clone모든 객체를 복제 하는 공용 메서드 를 생성하는 것이 가능할 수 있지만 이는이 를 필요로하는 클래스를 위해 특별히 작성된 메서드만큼 좋지 않을 것입니다.


하지만 왜 그것을 보호해야합니까?
Janusz

3
개체에서 사용하지 않도록 보호되어 있습니다 (어쨌든 예외가 발생합니다). 그들은 당신이 클래스에서 그것을 재정의하기를 원하고 당신은 그것을 공개합니다. (아래에 몇
Bill K

1
그리고 쓸모 아래에있는 내 지점에 따라 인터페이스를 고려할 때하는 것은
oxbow_lakes

재정의해야하는 것은 명확하지 않은 경우 추상이어야하고 객체 클래스에 있어서는 안됩니다. 왜 그런지 이해하려고 노력하고 있습니다.
Kumar Abhishek

4

Clone 메서드는 어떤 개체에서도 직접 사용할 수 없으므로 하위 클래스에 의해 재정의되도록되어 있습니다.

물론 공개 될 수 있고 복제가 불가능할 때 적절한 예외를 던질 수 있지만 오해의 소지가 있다고 생각합니다.

지금 복제가 구현되는 방식은 복제를 사용하려는 이유와 개체를 복제하는 방법에 대해 생각하게합니다.


2

기본 구현이 모든 필드 (개인용 포함)의 얕은 멤버 별 복사를 수행하고 constructor를 우회 하기 때문에 보호됩니다 . 이것은 객체가 처음에 처리하도록 설계된 것이 아닙니다 (예를 들어, 공유 목록에서 생성 된 객체 인스턴스를 추적하거나 이와 유사한 것).

같은 이유로 기본 구현은 clone()호출 된 객체가 Cloneable. 광범위한 결과를 초래할 수있는 잠재적으로 안전하지 않은 작업이므로 클래스 작성자는 명시 적으로 옵트 인해야합니다.


실제로 기본 구현 (객체 내)은 문서에 따라 예외를 발생시킵니다 ...
Bill K

2
아니, 그냥 던지지 않습니다. JavaDoc에서 : "Object 클래스의 메소드 복제는 특정 복제 작업을 수행합니다. 먼저이 객체의 클래스가 Cloneable 인터페이스를 구현하지 않으면 CloneNotSupportedException이 발생합니다. 모든 배열은 인터페이스 Cloneable을 구현하는 것으로 간주됩니다. 그렇지 않으면이 메서드는이 개체의 클래스의 새 인스턴스를 만들고 할당에 의한 것처럼이 개체의 해당 필드 내용으로 모든 필드를 초기화합니다. 필드 내용 자체는 복제되지 않습니다. "
Pavel Minaev

2

복제 가능의 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을 호출 할 수 있지만 원하는 결과 나 예외가 아닌 대부분의 시간을 제공합니다. 그러나 복제 가능을 구현하는 경우에만 권장됩니다.


2
당신은 할 수없는 그것을 보호 있기 때문에, 모든 객체에 복제를 호출!
Pavel Minaev

2

IMHO는 다음과 같이 간단합니다.

  • #clone 복제 할 수없는 개체에서 호출해서는 안되므로 공개되지 않습니다.
  • #cloneObject올바른 클래스의 얕은 복사본을 얻으려면 Cloneable을 구현 하는 하위 클래스 ob에 의해 호출되어야합니다.

하위 클래스에서 호출 할 수 있지만 다른 클래스에서는 호출 할 수없는 메서드의 올바른 범위는 무엇입니까?

그것은이다 protected.

Cloneable물론 구현 하는 클래스 는이 메서드를 공개하므로 다른 클래스에서 호출 할 수 있습니다.


0

Clone () 메소드는 내부적으로 'instance of Cloneable 여부'를 확인합니다. 이것은 Java 팀이 clone () method.clone () 메소드의 부적절한 사용을 제한 할 것이라고 생각할 수있는 방법입니다. 즉, 하위 클래스에서만 액세스됩니다. object는 모든 하위 클래스의 부모 클래스이므로 위의 'instance of Cloneable'확인이 없으면 모든 클래스에서 실제로 Clone () 메서드를 사용할 수 있습니다. 이것이 Java 팀이 clone () 메소드 'Cloneable의 인스턴스입니까'를 확인하여 clone ()의 부적절한 사용을 제한하려고 생각한 이유입니다.

따라서 cloneable을 구현하는 클래스는 Object 클래스의 clone () 메서드를 사용할 수 있습니다.

또한 보호되어 있기 때문에 복제 가능한 인터페이스를 구현하는 하위 클래스에서만 사용할 수 있습니다. 우리가 그것을 공개하고 싶다면,이 메소드는 그것의 자체 구현으로 서브 클래스에 의해 재정의되어야합니다.


-2

네, 제가 만난 것과 같은 문제입니다. 하지만이 코드를 구현하여 해결합니다.

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;
    }
}

누군가가 말했듯이.


1
CloneNotSupportedException은 선택 해제해야하는 확인 된 예외의 또 다른 예입니다 (즉, 예외가 아닌 RuntimeException을 확장해야 함). Side 클래스의 clone () 메서드는 Cloneable을 구현하므로 CloneNotSupportedException을 throw하지 않지만 Side.clone ()은 여전히 ​​예외를 포착하거나 선언해야합니다. 이것은 clone () 메서드에 불필요한 예외 처리 노이즈를 추가 할뿐입니다.
Derek Mahar

-2

글쎄요, 또한 태양 개발자들은 인간 일뿐입니다. 그들은 실제로 복제 메소드를 보호 된 것으로 구현하는 데 큰 실수를 저질렀습니다. ArrayList에서 작동하지 않는 복제 메소드를 구현 한 것과 같은 실수였습니다! 따라서 일반적으로 경험 많은 Java 프로그래머조차도 복제 방법에 대해 훨씬 더 깊은 오해가 있습니다.

그러나 최근에 빌드 방법과 포함 내용에 관계없이 모든 콘텐츠와 함께 모든 개체를 복사하는 빠르고 쉬운 솔루션을 찾았습니다. 여기에서 내 대답을 참조하십시오. Object.clone () 사용시 버그


-3

다시 말하지만, Java JDK 프레임 워크는 훌륭한 사고를 보여줍니다.

복제 가능한 인터페이스에 "public T clone ();"이 없습니다. 메서드는 인스턴스를 복제 할 수 있도록하는 속성 (예 : 직렬화 가능)처럼 작동하기 때문입니다.

이 디자인에는 다음과 같은 이유로 잘못된 것이 없습니다.

  1. Object.clone ()은 사용자 정의 클래스로 원하는 작업을 수행하지 않습니다.

  2. Myclass가 Cloneable을 구현 한 경우 => "public MyClass clone ()"으로 clone ()을 덮어 씁니다.

  3. MyInterface가 Cloneable을 확장하고 MyInterface를 구현하는 일부 MyClass가있는 경우 : 간단히 "public MyInterface clone ();"을 정의하십시오. 인터페이스 및 MyInterface 개체를 사용하는 모든 메서드에서 MyClass 클래스에 관계없이 복제 할 수 있습니다.


2
클래스가 상속되는 경우 파생 클래스 복제 구현은 기본 클래스 구현이 안전한 복제 메서드를 제공 할 때까지 안전하지 않습니다. 또한 메소드 / 속성이없는 인터페이스를 갖는 것은 일종의 특이한 디자인 조건입니다. 이 인터페이스는 클래스가 복제를 구현하도록 강제하지 않습니다.
prap19
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.