Java在自定义克隆期间检测循环引用
我正在为每个实体编写一个自定义克隆方法。对于深度复制,有没有一种方法可以检测循环引用,或者我必须手动找出它,并将克隆限制为单向而不是双向的Java在自定义克隆期间检测循环引用,java,Java,我正在为每个实体编写一个自定义克隆方法。对于深度复制,有没有一种方法可以检测循环引用,或者我必须手动找出它,并将克隆限制为单向而不是双向的 例如,我们使用hibernate,因此用户对象有一个对地址的引用,而地址有一个对用户的引用。尝试查看是否可以在不遇到循环引用问题的情况下对地址和用户进行深度复制要实现这一点,您需要一个已克隆对象的引用映射。我们实现了如下深度克隆: 在我们的实体基类中: public void deepClone() { Map<EntityBase,Entit
例如,我们使用hibernate,因此用户对象有一个对地址的引用,而地址有一个对用户的引用。尝试查看是否可以在不遇到循环引用问题的情况下对地址和用户进行深度复制要实现这一点,您需要一个已克隆对象的引用映射。我们实现了如下深度克隆: 在我们的实体基类中:
public void deepClone() {
Map<EntityBase,EntityBase> alreadyCloned =
new IdentityHashMap<EntityBase,EntityBase>();
return deepClone(this,alreadyCloned);
}
private static EntityBase deepClone(EntityBase entity,
Map<EntityBase,EntityBase> alreadyCloned) {
EntityBase clone = alreadyCloned.get(entity);
if( clone != null ) {
return alreadyClonedEntity;
}
clone = newInstance(entity.getClass);
alreadyCloned.put(this,clone);
// fill clone's attributes from original entity. Call
// deepClone(entity,alreadyCloned)
// recursively for each entity valued object.
...
}
/**
* Perform a deep clone.
*
* @return Deep Clone.
* @throws CloneNotSupportedException
*/
@SuppressWarnings("unchecked")
public VersionedEntityImpl deepClone() throws CloneNotSupportedException {
Map<VersionedEntityImpl, VersionedEntityImpl> alreadyCloned = new IdentityHashMap<VersionedEntityImpl, VersionedEntityImpl>();
return deepClone(this, alreadyCloned);
}
/**
* Perform a deep clone.
*
* @param entity
* @param alreadyCloned
* @return Deep Clone.
* @throws CloneNotSupportedException
*/
@SuppressWarnings("unchecked")
protected VersionedEntityImpl deepClone(VersionedEntityImpl entity,
Map<VersionedEntityImpl, VersionedEntityImpl> alreadyCloned) throws CloneNotSupportedException {
if (entity != null) {
VersionedEntityImpl clone = alreadyCloned.get(entity);
if (clone != null) {
return clone;
}
clone = entity.clone();
alreadyCloned.put(entity, clone);
return entity.deepCloneEntity(clone, alreadyCloned);
}
return null;
}
/**
* Method performing a deep clone of an entity (circles are eliminated automatically). Calls
* deepClone(entity,alreadyCloned) recursively for each entity valued object.
*
* @param clone
* @param alreadyCloned
* @return clone
* @throws CloneNotSupportedException
*/
protected abstract VersionedEntityImpl deepCloneEntity(VersionedEntityImpl clone,
Map<VersionedEntityImpl, VersionedEntityImpl> alreadyCloned) throws CloneNotSupportedException;
public void deepClone(){
映射ALREADCYCLONED=
新标识hashmap();
返回deepClone(此,已循环);
}
私有静态EntityBase deepClone(EntityBase实体,
地图(已清除){
EntityBase clone=alreadCyclone.get(实体);
如果(克隆!=null){
返回实体;
}
clone=newInstance(entity.getClass);
放(这个,克隆);
//从原始实体填充克隆的属性。调用
//deepClone(实体,已环化)
//递归地为每个实体值对象。
...
}
@Daniel:非常感谢您的回答
我只是使用了您的代码,并根据我的需要对其进行了一些修改,这使得它更易于与子类一起使用。也许其他人也对此感兴趣,所以下面是我的基类代码:
public void deepClone() {
Map<EntityBase,EntityBase> alreadyCloned =
new IdentityHashMap<EntityBase,EntityBase>();
return deepClone(this,alreadyCloned);
}
private static EntityBase deepClone(EntityBase entity,
Map<EntityBase,EntityBase> alreadyCloned) {
EntityBase clone = alreadyCloned.get(entity);
if( clone != null ) {
return alreadyClonedEntity;
}
clone = newInstance(entity.getClass);
alreadyCloned.put(this,clone);
// fill clone's attributes from original entity. Call
// deepClone(entity,alreadyCloned)
// recursively for each entity valued object.
...
}
/**
* Perform a deep clone.
*
* @return Deep Clone.
* @throws CloneNotSupportedException
*/
@SuppressWarnings("unchecked")
public VersionedEntityImpl deepClone() throws CloneNotSupportedException {
Map<VersionedEntityImpl, VersionedEntityImpl> alreadyCloned = new IdentityHashMap<VersionedEntityImpl, VersionedEntityImpl>();
return deepClone(this, alreadyCloned);
}
/**
* Perform a deep clone.
*
* @param entity
* @param alreadyCloned
* @return Deep Clone.
* @throws CloneNotSupportedException
*/
@SuppressWarnings("unchecked")
protected VersionedEntityImpl deepClone(VersionedEntityImpl entity,
Map<VersionedEntityImpl, VersionedEntityImpl> alreadyCloned) throws CloneNotSupportedException {
if (entity != null) {
VersionedEntityImpl clone = alreadyCloned.get(entity);
if (clone != null) {
return clone;
}
clone = entity.clone();
alreadyCloned.put(entity, clone);
return entity.deepCloneEntity(clone, alreadyCloned);
}
return null;
}
/**
* Method performing a deep clone of an entity (circles are eliminated automatically). Calls
* deepClone(entity,alreadyCloned) recursively for each entity valued object.
*
* @param clone
* @param alreadyCloned
* @return clone
* @throws CloneNotSupportedException
*/
protected abstract VersionedEntityImpl deepCloneEntity(VersionedEntityImpl clone,
Map<VersionedEntityImpl, VersionedEntityImpl> alreadyCloned) throws CloneNotSupportedException;
/**
*执行深度克隆。
*
*@return深克隆。
*@CloneNotSupportedException
*/
@抑制警告(“未选中”)
public versionIdentityImpl deepClone()引发CloneNotSupportedException{
Map ALREADCYCLONED=新标识HASHMAP();
返回deepClone(此,已循环);
}
/**
*执行深度克隆。
*
*@param实体
*@param-alreadcycloned
*@return深克隆。
*@CloneNotSupportedException
*/
@抑制警告(“未选中”)
受保护的VersionIdentityImpl深度克隆(VersionIdentityImpl实体,
映射ALREADCYCLONED)抛出CloneNotSupportedException{
如果(实体!=null){
VersionIdentityImpl clone=alreadCyclone.get(实体);
如果(克隆!=null){
返回克隆;
}
clone=entity.clone();
alreadcycloned.put(实体,克隆);
返回实体.deepCloneEntity(克隆,已克隆);
}
返回null;
}
/**
*方法执行实体的深度克隆(自动消除圆)。电话
*对每个实体值对象递归地进行deepClone(实体,alreadcycloned)。
*
*@param克隆
*@param-alreadcycloned
*@returnclone
*@CloneNotSupportedException
*/
受保护的抽象VersionIdentityImpl deepCloneEntity(VersionIdentityImpl克隆,
Map ALREADCYCLONED)抛出CloneNotSupportedException;
将什么放入子类中:
@SuppressWarnings("unchecked")
@Override
protected VersionedEntityImpl deepCloneEntity(VersionedEntityImpl clone,
Map<VersionedEntityImpl, VersionedEntityImpl> alreadyCloned) throws CloneNotSupportedException {
// fill clone's attributes from original entity. Call
// deepClone(entity,alreadyCloned)
// recursively for each entity valued object.
if (this.associatedItems != null) {
List<SomeClass> listClone = new LinkedList<SomeClass>();
for (SomeClass someClass: this.associatedItems) {
listClone.add((SomeClass) super.deepClone(someClass, alreadyCloned));
}
((SomeOtherClass) clone).setAssociatedItems(listClone);
}
((SomeOtherClass) clone).setYetAnotherItem((YetAnotherClass) super.deepClone(this.yai, alreadyCloned));
return clone;
}
@SuppressWarnings(“未选中”)
@凌驾
受保护的VersionIdentityImpl deepCloneEntity(VersionIdentityImpl克隆,
映射ALREADCYCLONED)抛出CloneNotSupportedException{
//从原始实体填充克隆的属性。调用
//deepClone(实体,已环化)
//递归地为每个实体值对象。
if(this.associatedItems!=null){
List listClone=new LinkedList();
for(SomeClass SomeClass:this.associatedItems){
添加((SomeClass)super.deepClone(SomeClass,alreadcycloned));
}
((SomeOtherClass)克隆).setAssociatedItems(listClone);
}
((SomeOtherClass)clone.setYetAnotherItem((YetAnotherClass)super.deepClone(this.yai,alreadcycloned));
返回克隆;
}
到目前为止,它还不是完美的,但目前它已经很好地完成了工作:)要处理循环引用,可以使用IdentityMap。这将跟踪它找到的每个对象,当您序列化或复制数据时,可以使用它来确保正确处理重复的对象。e、 g.在一个结构中,您可能多次使用同一个对象,而不想将它们转换为不同的对象。在这种情况下使用HashMap是一个糟糕的主意(两者都可能是假的,而且速度很慢)。IdentityHashMap好多了。+1条很好的评论。更新了我的答案并修复了我自己的代码:),但我必须承认HashMap并不慢。HashMap和IdentityHashMap之间的慢度差异取决于键的.hashCode和.equals实现。如果这些都不好,HashMap就会变慢(在这个算法中,你可能会得到错误的结果,比如合并不同的对象,因为它们是相等的)。@Daniel,在put和类似树的结构上进行分配对于哈希表来说是一个很高的(而且是不必要的)代价。您可以拥有完全无锁(并发)的hashmap,在put上没有分配。顺便说一句,IdentityHashMap(不使用相对较慢的虚拟调用
Object.hashCode
)使用线性探测内部结构,该结构在所有可能的方面都优于HashMap的树。在以下情况下,您的代码将无法工作:地址既有用户对象,也有createby用户对象,并由用户对象修改。