2009-03-19 2 views
7

개체의 인스턴스화 대신 복제를 사용하는 오래된 Java 코드베이스 (jvm 1.4)를 유지하려고합니다. 성능 최적화라고 생각합니다. 여기에 인위적인 예제 : 어떤 점에서이 사실 추천 관용구이었다에도 불구하고 조기 최적화에 대한복제는 생성자/팩토리 메소드보다 성능이 향상 되었습니까?

public class Foo { 
    private SomeObject obj; // SomeObject implements Cloneable 
    public Foo() { 
    obj = new SomeObject(); 
    obj.setField1("abc"); // these fields will have the same value every time 
    obj.setField2("def"); 
    } 
    public void doStuff() { 
    SomeObject newObj = obj.clone(); // clone it instead of using a factory method 
    // do stuff with newObj 
    } 
} 

일반적인주의 사항?

+0

이상하게 보입니다. 나는 새로운 객체 인스턴스화를 위해 생성자를 사용할 것이다. –

답변

3

복사 생성자 또는 팩토리 메서드 대신 clone()을 호출하는 한 가지 이유는 다른 옵션을 사용할 수 없다는 것입니다.

얕은 개체 복사본 (딥 복사본이 더 많이 포함됨)을 수행하기 위해 clone()을 구현하는 것은 복사 연산 자나 팩토리 메서드를 구현하여 동일한 작업을 수행하는 것과 비교하면 간단합니다. clone()을 구현하려면 클래스가 Cloneable 인터페이스를 구현하고 Object.clone()을 호출하는 을 호출하는 메서드로 clone()을 재정의해야합니다. Object.clone()은 원본 개체의 모든 속성을 복제본의 해당 속성에 복사하여 얕은 복사본을 만듭니다.

clone()을 구현하는 것이 간단하지만 Cloneable을 구현하는 것을 잊지 마시기 바랍니다. 따라서 clone()을 사용하여 개체를 복제 할 때 발생할 수있는 위험은 해당 개체의 클래스가 Cloneableclone()을 직접 또는 간접적으로 호출하면 CloneNotSupportedException이 발생합니다.

Cloneable 인터페이스의 poor design에서이 code example과 이전 discussion을 참조하십시오.

4

아마 그들은 사본을 원했습니다. 아마도 그들은 그것을 다른 함수에 전달하려고하고 아마도 그 함수가 그것을 변경하지 않을 것이라고 확신 할 수 없습니다. 이것은 doStuff() 메소드가 호출 된 Foo 객체의 상태와 관련하여 const라는 것을 확인하는 방법입니다.

+0

이 질문에 +1을하면 (코드를 본 후) 내 비법적인 답변보다 적용 가능성이 높거나 더 많이 나타납니다. – MarkusQ

+0

이것이 복제의 주된 목적이라는 점에 유의하십시오 (교수님은 자신이 말하는 것에 대해 알고 있다고 가정). – Chris

+0

+1 : 그래, 여기에 보인다. .clone()은 값으로 전달하는 자바 방식이다. –

1

생성자에서 수행되는 작업량에 따라 성능 최적화가 될 수 있습니다.

의미가 다르므로 사용 가능성이 높습니다. 복제는 일반적으로 그런 방식으로 사용하지 않는 언어로 "프로토 타입 의미"(예 : 자바 스크립트, 자체 등)를 구현하는 방법을 제공합니다.

+0

어떻게 그렇게됩니까? 프로토 타입 의미론은 런타임에서 생성자 또는 다른 필드 또는 메서드의 동작을 변경할 수 있음을 의미합니다. –

+0

복제를 사용하면 초기 값 등을 설정할 수 있으며 (대리자를 사용하여) 동작을 변경할 수도 있습니다. 그것은 일종의 괴상한 일이지만, 일반적으로 셀프 스타일의 의미를 완전히 발휘하지는 않습니다. 단지 약간의 주스이기 때문에 실제로는 실제로 작동합니다. – MarkusQ

0

SomeObject 생성자가 데이터베이스에서 무언가를 파지하거나 무언가를 파싱하거나 파일에서 무언가를 읽는 것과 같이 값 비싼 작업을하는 경우 복제 작업이 수행되지 않도록하는 것이 좋습니다.

생성자가 아무것도 수행하지 않으면 실제로 복제를 사용할 필요가 없습니다.

편집 : 그 클론을 표시하는 추가 코드는 생성자와 같은 일을 할 필요가 없습니다 :

class Main 
    implements Cloneable 
{ 
    private final double pi; 

    public Main() 
    { 
     System.out.println("in Main"); 
     // compute pi to 1,000,000,000 decimal palaces 
     pi = 3.14f; 
    } 

    public Object clone() 
    { 
     try 
     { 
      return (super.clone()); 
     } 
     catch(final CloneNotSupportedException ex) 
     { 
      throw new Error(); // would not throw this in real code 
     } 
    } 


    public String toString() 
    { 
     return (Double.toString(pi)); 
    } 

    public static void main(String[] args) 
    { 
     final Main a; 
     final Main b; 

     a = new Main(); 
     b = (Main)a.clone(); 

     System.out.println("a = " + a); 
     System.out.println("b = " + b); 
    } 
} 

메인 생성자가 한 번, 컴퓨팅 파이 한 번 수행이라고합니다.

+0

당신이 그것에 대해 부정확하다고 느끼는 것에 대해 적어도 코멘트를하면됩니다. – TofuBeer

+0

복사 생성자가 값 비싼 작업을 수행 한 경우 복제 작업도 동일하게 수행해야합니다. –

+0

복제본이 생성자를 우회합니다. 어떻게하면 동일한 작업을 수행해야합니까? – TofuBeer

2

복사 생성자의 주요 문제점 중 하나는 컴파일 타임에 개체 유형을 알아야한다는 것입니다.상속 가능한 클래스가 복사 생성자를 지원하고 생성자가 파생 클래스 객체를 전달하면 생성자는 전달 된 객체의 기본 클래스 속성과 일반적으로 일치하는 기본 클래스 객체를 생성하지만 새 객체는 ' 기본 클래스에없는 전달 된 객체에있는 모든 기능을 지원할 수 없습니다.

복사 생성자를 "protected"로 설정하고 해당 클래스의 자체 복사 생성자를 호출하는 모든 파생 클래스에서 재정의 가능한 팩토리 복사 메서드를 사용하면이 문제를 다소 해결할 수 있습니다.이 복사 생성자는 해당베이스의 복사 생성자를 호출합니다 수업. 모든 파생 클래스는 복사 생성자와 복사 메소드의 재정의가 필요합니다. 그러나 새로운 필드를 추가할지 여부는 상관 없습니다. 케이스 클래스가 "복제"를 사용하면이 여분의 코드를 제거 할 수 있습니다.

관련 문제