Java обнаруживает циклические ссылки во время пользовательского клонирования - PullRequest
5 голосов
/ 01 марта 2011

Я пишу собственный метод клонирования для каждой сущности. для глубокого копирования есть способ обнаружить циклические ссылки или мне нужно вручную выяснить это и ограничить клонирование, чтобы оно было однонаправленным, а не двунаправленным.

Например, мы используем hibernate, следовательно, объект User имеет ссылку на Address, а Address имеет ссылку на User. Попытка выяснить, возможно ли сделать глубокую копию адреса, а также пользователя, не сталкиваясь с проблемами циклической ссылки

Ответы [ 2 ]

7 голосов
/ 01 марта 2011

Для реализации вам понадобится Карта ссылок на уже клонированные объекты.Мы реализовали глубокий клон примерно так:

В базовом классе нашей сущности:

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.
    ...
}
1 голос
/ 29 мая 2012

@ Даниэль: Большое спасибо за этот замечательный ответ!

Я просто использовал ваш код и немного изменил его в зависимости от своих потребностей, что облегчает его использование с подклассами. Возможно, кому-то еще это интересно, поэтому вот мой код для базового класса:

/**
 * 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;

Что поместить в подклассы:

@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;
}

Пока он не идеален, но на данный момент хорошо справляется с работой :) 1009 *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...