复制有关Java的构造函数问题
我有一个关于Java中副本构造的问题。考虑下面的类; 在复制构造函数中,我可以说new(Integer(other.id))来获得传递给构造函数的新Integer对象,但不能说newt(other.data)正如编译器会说的那样,无法实例化类型T。我如何确保在复制构造泛型项时,它不会只传递引用,这样两个对象将共享底层数据 另外,在getLinks方法中,它正在执行一个新的操作并创建列表的一个新对象,但是它将深度复制并创建列表中包含的项的新对象,还是只包含对现有对象列表项的引用,这样您就有两个列表都指向相同的数据。请参见下面的注释/代码。提前感谢您的专业知识复制有关Java的构造函数问题,java,constructor,copy-constructor,Java,Constructor,Copy Constructor,我有一个关于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();
}
}