复制有关Java的构造函数问题

复制有关Java的构造函数问题,java,constructor,copy-constructor,Java,Constructor,Copy Constructor,我有一个关于Java中副本构造的问题。考虑下面的类; 在复制构造函数中,我可以说new(Integer(other.id))来获得传递给构造函数的新Integer对象,但不能说newt(other.data)正如编译器会说的那样,无法实例化类型T。我如何确保在复制构造泛型项时,它不会只传递引用,这样两个对象将共享底层数据 另外,在getLinks方法中,它正在执行一个新的操作并创建列表的一个新对象,但是它将深度复制并创建列表中包含的项的新对象,还是只包含对现有对象列表项的引用,这样您就有两个列表

我有一个关于Java中副本构造的问题。考虑下面的类; 在复制构造函数中,我可以说new(Integer(other.id))来获得传递给构造函数的新Integer对象,但不能说newt(other.data)正如编译器会说的那样,无法实例化类型T。我如何确保在复制构造泛型项时,它不会只传递引用,这样两个对象将共享底层数据

另外,在getLinks方法中,它正在执行一个新的操作并创建列表的一个新对象,但是它将深度复制并创建列表中包含的项的新对象,还是只包含对现有对象列表项的引用,这样您就有两个列表都指向相同的数据。请参见下面的注释/代码。提前感谢您的专业知识

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();
    }
}
类有向图节点
{
整数id;
T数据;
ArrayList链接;
公共有向图节点(整数i)
{
id=i;
links=newarraylist();
}
公共有向图节点(整数i,td)
{ 
id=i;数据=d;
links=newarraylist();
}
公共有向图节点(有向图节点其他)
{
other.id=新整数(other.id);
other.data=other.data;//有问题的行
this.links=other.getLinks();//还将创建一个包含引用的新列表
//或者它会深度复制列表中包含的项目?
//请参阅下面的getLinks()方法
}
公共void setData(td){data=d;}
public void addLink(DigraphNode n){links.add(n);}
public void addLinks(ArrayList ns){links.addAll(ns);}
公共ArrayList getLinks()
{
返回新的ArrayList(链接);
}
public void printNode()
{
系统输出打印(“Id:+Id+”链接:);
for(有向图节点i:链接)
{
系统输出打印(i.id+“”);
}
System.out.println();
}
}
  • 您不能像尝试的那样实例化
    new t(other.data)
    ,但是如果
    t实现了可克隆性,您可以
    clone()
    other.data
  • 每次调用
    getLinks()
    都会创建一个新的列表,其中引用了
    链接所包含的对象,您必须使用内部具有相同引用的不同列表(因此更改一个引用对象属性将反映到另一个列表对象,因为它们是相同的对象)
  • 关于
    arraylistlinks=newarraylist()来自Oracle文档:

    实例变量的初始值设定项块看起来就像静态的 初始值设定项阻止,但不包含static关键字:
    {
    //初始化所需的任何代码都在这里
    }
    Java编译器将初始值设定项块复制到每个构造函数中。因此,此方法可用于共享一个数据块 多个构造函数之间的代码
  • 编辑:
    您可以定义一个静态方法(
    copy
    ),该方法尝试使用所有可能的策略来复制泛型对象;最好的方法是定义您自己的接口来分离您自己的状态,并模拟一种复制构造函数(如果需要,您可以重用
    copy
    方法),或者通过序列化,或者像上次尝试一样,使用克隆(但是
    clone()
    充满了陷阱)。
    您还可以使用以下库:


    接口MyCloneableInterface{
    T复制(T对象)抛出CopyException;
    }
    公共静态T复制(T数据)引发CopyException{
    if(data==null)返回null;
    if(MyCloneableInterface的数据实例){
    返回((MyCloneabeInterface)数据)。重复(数据);
    }
    if(可序列化的数据实例){
    试一试{
    ByteArrayOutputStream bas=新的ByteArrayOutputStream();
    ObjectOutputStream oos=新的ObjectOutputStream(BAS);
    oos.writeObject(本);
    ByteArrayInputStream bais=新的ByteArrayInputStream(baos.toByteArray());
    ObjectInputStream ois=新ObjectInputStream(BAI);
    返回(CloneExample)ois.readObject();
    }
    捕获(…){//rethrow}
    }
    if(可克隆的数据实例){
    试一试{
    返回(T)data.clone();
    }
    catch(CloneNotSupportedException e){//rethrow}
    }
    //否则,您可以通过反射或
    //正在通过反射逐场克隆对象。。。
    }
    
    第一个问题:不能实例化泛型实例(换句话说,调用
    T
    的构造函数)。您应该定义
    T implements Cloneable
    并调用
    clone
    ,或者如果
    T
    始终在您的控制下,则使用您自己的另一个界面。这个方法有很多陷阱,我建议您首先阅读这个接口并熟悉这些陷阱(您可以在“有效的Java”一书中找到关于这个的一个很好的章节)。此外,您并不总是能够保证此类将使用
    T
    类型,这些类型是
    可克隆的

    关于
    链接
    -您在开始时实例化它,然后在构造函数中重写它-为什么?删除初始化。
    getLinks
    的工作方式不是创建深度副本。意思-您将获得一个新列表,该列表本身将与原始列表不同,但项目将是浅拷贝

    关于你的最后一个问题——正如我已经说过的,这是多余的。删除开头的初始化。在创建对象时,不要使用它,而是将其留给垃圾收集。为了避免在每个构造函数中调用此函数,可以执行以下操作:

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

    对所有有用的答案进行了投票,但我在下面回答我自己的问题,其中显示了更新的代码。我想看看有人会如何为泛型实现一个副本,但没有人为此发布代码,所以我推出了自己的。见下面我的答案

    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();
        }
    }
    
    import java.lang.reflect.*;
    导入java.util.*;
    类缺失
    
    public DigraphNode(T val) {
        this();
        this.data = val;
    }
    
    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();
        }
    }