2013-08-17 3 views
2

Java의 복사 생성에 대한 질문이 있습니다. 다음 클래스를 고려하십시오.Java에 대한 생성자 질문 복사

복사 생성자에서 new (Integer (other.id))를 호출하여 생성자에 전달되는 새 정수 객체를 가져올 수 있지만 컴파일러에서 말하는 것처럼 새 T (other.data)를 말할 수는 없습니다. 유형 T를 인스턴스화 할 수 없습니다. 일반 항목이 복사 된 경우 2 개의 객체가 기본 데이터를 공유하도록 참조를 전달하지 않을 것입니다.

또한 getLinks 메소드에서 새로운 작업을 수행하고 목록의 새 오브젝트를 작성하지만 목록에 포함 된 항목의 새로운 오브젝트를 작성하거나 새 오브젝트를 작성하거나 기존 오브젝트에 대한 참조 만 포함하게됩니다 객체는 같은 데이터를 가리키는 2 개의리스트를 가지도록 아이템을 나열합니다. 아래 주석/코드를 참조하십시오. 전문성에 미리 감사드립니다.

class DigraphNode<T> 
{ 
    Integer id; 
    T data; 
    ArrayList<DigraphNode<T> > links; 

    public DigraphNode(Integer i) 
    { 
     id = i; 
     links = new ArrayList<DigraphNode<T> >(); 
    } 
    public DigraphNode(Integer i, T d) 
    { 
     id = i; data = d; 
     links = new ArrayList<DigraphNode<T> >(); 
    } 

    public DigraphNode(DigraphNode<T> other) 
    { 
     other.id = new Integer(other.id); 
     other.data = other.data; // line in question 
     this.links=other.getLinks(); // also will create a new list with references 
            // or will it deep copy the items contained in the list? 
            // see getLinks() method below 
    } 

    public void setData (T d) { data = d; } 
    public void addLink (DigraphNode<T> n) { links.add(n); } 
    public void addLinks (ArrayList<DigraphNode<T> > ns) { links.addAll(ns); } 

    public ArrayList<DigraphNode<T> > getLinks() 
    { 
     return new ArrayList<DigraphNode<T> >(links); 
    } 

    public void printNode() 
    { 
     System.out.print("Id: " + id + " links: "); 
     for (DigraphNode<T> i : links) 
     { 
      System.out.print(i.id + " "); 
     } 
     System.out.println(); 
    } 
} 
+0

시도 그래서 나는 그들을 함께 총괄 어떤 문제를 보지 못했다 생성자와 질문 – aaronman

+0

그들은 모두 같은 클래스에 관련된 모든 당 하나 개의 질문을합니다. 윤곽을 그리기 위해 별도의 단락을 만들었습니다. 향후 게시물에 대한 귀하의 조언을 고려하거나 취할 것입니다. 감사. – bjackfly

+1

그냥 답을 얻을 수 있도록 돕기 위해 사람들은 재미있는 질문이라고 생각하지 않으면 사람들이 텍스트 벽을 읽지 않으려 고합니다. 간단한 질문을 짧게 유지하는 것이 가장 좋습니다 – aaronman

답변

1

  1. 당신이 노력과 같이 new T(other.data)를 인스턴스화 할 수 없지만, 할 수 clone() other.data T implements Cloneable
  2. 경우 getLinks()에 대한 모든 호출을 참조하여 새 목록을 만들 것은 links에 포함 된 객체에, 당신 동일한 참조가있는 서로 다른 목록에 있어야 함 (하나의 참조 객체 속성을 변경하면 같은 객체이기 때문에 다른 목록 객체에 반영됩니다)
  3. ArrayList<> links = new ArrayList<>(); 오라클의 문서 :

    인스턴스 변수에 대한

    초기화 블록 정적 인 초기화 블록처럼,하지만 static 키워드없이 볼 :

    자바 컴파일러 사본 {// 어떤 코드가 초기화에 필요한
    여기
    간다} 모든 생성자에 이니셜 라이저 블록. 따라서이 방법을 사용하여 여러 생성자간에 코드 블록을 공유 할 수 있습니다.

편집 :
가능한 모든 전략을 사용하여 일반 개체를 복사하려고하는 정적 메서드 ( copy)를 정의 할 수 있습니다. 가장 좋은 방법은 자신의 인터페이스를 정의하여 자신의 상태를 정의하고 일종의 복사 생성자를 시뮬레이트하는 것입니다 (원할 경우 copy 메서드를 다시 사용할 수 있습니다). 그렇지 않으면 직렬화를 통해 또는 마지막 시도에서 복제를 사용합니다 (그러나 clone()이 가득 찼습니다. 함정).
또한이 라이브러리를 사용할 수 있습니다


interface MyCloneableInterface<T> { 
    T duplicate(T object) throws CopyException; 
} 
public static <T> T copy(T data) throws CopyException { 
    if(data == null) return null; 
    if(data instanceof MyCloneableInterface) { 
    return ((MyCloneabeInterface)data).duplicate(data); 
    } 
    if(data instanceof Serializable) { 
    try { 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     ObjectOutputStream oos = new ObjectOutputStream(baos); 
     oos.writeObject(this); 

     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 
     ObjectInputStream ois = new ObjectInputStream(bais); 
     return (CloneExample) ois.readObject(); 
    } 
    catch(...) {//rethrow} 
    } 
    if(data instanceof Cloneable) { 
    try { 
     return (T)data.clone(); 
    } 
    catch(CloneNotSupportedException e) {//rethrow} 
    } 
    // else you can look for copy-constructor via reflection or 
    // cloning object field-by-field via reflection... 
} 
+0

클래스가 복제를 지원하는 경우 other.data를 복제 할 수 있습니다. –

+0

감사합니다. 업데이트가 도움이되었습니다. – bjackfly

1

첫 번째 질문 : 다른 단어 T 전화에 당신은 (일반 인스턴스를 인스턴스화 할 수 없습니다 ' 생성자). 을 정의하고 clone으로 전화하거나 T이 항상 사용자가 제어 할 수있는 경우 사용자 자신의 다른 인터페이스를 사용해야합니다. 이 방법에는 여러 가지 함정이 있습니다. 먼저이 인터페이스에 대해 읽고 함정에 대해 익숙해지기를 권합니다 ("Effective Java"책에서이 장을 참조하십시오).또한이 클래스가 인 T 유형을 사용할 것이라고 항상 보장 할 수있는 것은 아닙니다.

links - 처음에는 인스턴스화 한 다음 생성자에서 재정의합니다. - 왜? 초기화를 제거하십시오. 귀하의 getLinks 작동 방식은 깊은 사본을 작성하는 것이 아닙니다. 의미 - 당신은 새로운 목록을 얻을거야, 목록 자체가 원래 목록과 다를 수 있지만, 항목은 얕은 복사 될 것입니다.

마지막 질문에 대해 - 제가 이미 말했듯이, 그것은 중복됩니다. 처음부터 초기화를 제거하십시오. 당신은 객체를 생성하고 그것을 사용하지 않고 가비지 콜렉션을 위해 남겨 둡니다. 당신이 모든 생성자이 호출 피하기 위해 할 수있는 것은이 같은 것입니다 :

public DigraphNode() { 
    links = new ArrayList<DigraphNode<T> >(); 
} 

그리고 다른 생성자 예를 들어,이 생성자를 호출 있습니다

public DigraphNode(T val) { 
    this(); 
    this.data = val; 
} 
+0

복사 생성자의 링크 만 덮어 씁니다. 정규 생성자에서는 그것을 오버라이드하지 않습니다. 비록 포인트가 취해졌지만 복사 생성자를 인스턴스화하지 않도록 변경했지만 언급 한 시나리오를 피하기 위해 데이터 멤버를 복사하고 아래에 언급 된 @bellabax와 같이 생성자 또는 이니셜 라이저 블록으로 초기화를 이동합니다. – bjackfly

+0

어쨌든 좋은 연습이라고 생각합니다. 사용되지 않는 객체를 생성하지 말고 기본 생성자에 대한 호출을 사용하십시오. 아마 당신은 특정한 생성자와 다른 좀더 일반적인 생성자를 가지고 있기 때문에 나의 예제가 달라야한다. – Avi

+0

감사합니다. 제 의견을 업데이트했습니다. – bjackfly

0

Upvoted 모든 도움이 대답,하지만 난 대답하고 아래에 업데이트 된 코드를 보여주는 내 자신의 질문입니다. 나는 누군가가 generic을위한 copy를 구현하는 방법을보고 싶었지만 아무도 그것을위한 코드를 게시하지 않았다. 그래서 나는 내 자신을 굴렸다. 내 대답 아래를 참조하십시오.

import java.lang.reflect.*; 
import java.util.*; 

class MissingDigraphNodeException extends Exception 
{ 
    private static final long serialVersionUID = 1000L; 
    public MissingDigraphNodeException(String message) 
    { 
     super(message); 
    } 
} 

class CopyException extends Exception 
{ 
    private static final long serialVersionUID = 2000L; 
    public CopyException(String message) 
    { 
     super(message); 
    } 
} 

class DigraphNode<T> 
{ 
    Integer id; 
    T data; 
    ArrayList<DigraphNode<T> > links; 

    public DigraphNode(Integer i) 
    { 
     id = i; 
     links = new ArrayList<DigraphNode<T> >(); 
    } 
    public DigraphNode(Integer i, T d) 
    { 
     id = i; data = d; 
     links = new ArrayList<DigraphNode<T> >(); 
    } 

    public DigraphNode(DigraphNode<T> other) 
    { 
     try 
     { 
      this.data = copy(other.data); 
     } 
     catch (CopyException e) 
     { 
      e.printStackTrace(); 
     } 
     this.links=other.getLinks(); 
     this.id = new Integer(other.id); 
    } 

    // is there a better way to copy a generic? 
    @SuppressWarnings("unchecked") 
    public T copy(T source) throws CopyException 
    { 
     Class<?> clzz = source.getClass(); 
     Method meth; 
     Object dupl = null; 
     try { 
      meth = clzz.getMethod("clone", new Class[0]); 
      dupl = meth.invoke(source, new Object[0]); 
     } catch (Exception e) 
     { 
      e.printStackTrace(); 
      throw new CopyException("Error: Copying Generic of T"); 
     } 
     return (T) dupl; 
    } 

    public void setData (T d) { data = d; } 
    public void addLink (DigraphNode<T> n) { links.add(n); } 
    public void addLinks (ArrayList<DigraphNode<T> > ns) { links.addAll(ns); } 

    public ArrayList<DigraphNode<T> > getLinks() 
    { 
     // return a new copy of the list 
     ArrayList<DigraphNode<T> > l = new ArrayList<DigraphNode<T> >(); 
     for (DigraphNode<T> i : links) 
     { 
      i.links.add(new DigraphNode<T>(i)); // use copy constructor 
     } 
     return l; 
    } 

    public void printNode() 
    { 
     System.out.print("Id: " + id + " links: "); 
     for (DigraphNode<T> i : links) 
     { 
      System.out.print(i.id + " "); 
     } 
     System.out.println(); 
    } 
} 
+0

만약 도움이된다면 편집을 읽어주세요 –

+0

당신의'copy' 구현 대신에 다음과 같이해야한다고 생각합니다 : 'if (source instanceof Cloneable) {T dupl = (T) ((Cloneable) source) .clone()); }' 'source'가'Cloneable'의 인스턴스가 아니라면 복제 메소드를 호출하는 것이 좋지 않습니다 (깊은 복사 구현이없는 경우 얕은 복사본에 만족하지 않는 한). – Avi

+0

감사합니다. 예,이 경우에는 전체 복사본이 필요하지 않으므로 얕은 복사본을 사용하게되었습니다. – bjackfly