2014-10-24 9 views
2

Хорошо известно, что Cloneable нарушен без ремонта (см. Обсуждение in this question для получения дополнительной информации).Современные альтернативы для клонирования?

Последние вопросы по альтернативам и "как делать это правильно" несколько лет:

Так что я хотел бы еще раз спросить:

Что современный день (2014) альтернативы Cloneable?

Я ищу универсальное решение. Я мог бы представить себе следующие требования:

  • Своего рода Copyable интерфейса, классы будут осуществлять: A extends Copyable.
  • Глубокое копирование. Если значение A указывает экземпляр B, a.copy() должен ссылаться на новый b.copy().
  • Скопировать на указанную цель: a.copyTo(a1).
  • Полиморфного копирование: если B расширяет A то a.copyTo(b) следует скопировать все свойства B от a к b.

Конечно, я могу реализовать все это самостоятельно, но разве было бы разумно иметь стандартные интерфейсы для этого? Или я чего-то не хватает?


Немного фона для моего контекста. Я много работаю с JAXB и классами, производными от схемы. Часто чрезвычайно полезно иметь глубокое копирование для этих классов. Несколько лет назад я написал пару плагинов компилятора схемы JAXB для генерации copyTo методов, которые выполняют требования выше (и более). Мне пришлось использовать свой собственный API времени выполнения. Теперь я пересматривал дело и решил спросить, есть ли стандартное решение.

+0

Что здесь точно «основано на мнениях»? – lexicore

ответ

2

Прежде всего, я не согласен с людьми, говоря, что Cloneable «ломается». Он не «сломан» - он делает именно то, что он документирует, чтобы вызвать Object.clone(), чтобы выбросить исключение или нет. Людям это не нравится, потому что они предполагают, что это то, чего нет - они предполагают, что это интерфейс для объектов, которые могут быть клонированы, что никогда не было тем, чем он должен был быть.

Java (все еще) не имеет интерфейса в стандартной библиотеке для объектов, которые могут быть клонированы. Было бы неплохо, если бы они добавили такой интерфейс, но они этого не сделали. Вы можете создать свой собственный интерфейс, и вы можете реализовать его собственные классы, но проблема в том, что вы не можете использовать существующие классы стандартной библиотеки. Так что это было бы полезно, если бы вы имели дело только с экосистемой ваших собственных классов.

+0

Как насчет других «почти-де-факто-стандартных» вещей? Не 'java *' пакеты, но что-то много людей используют? Как SLF4J для регистрации или Joda Time для обработки даты и времени? – lexicore

4

Механизм, который я использовал более одного раза, сериализуется/десериализуется. Конечно, это работает только в том случае, если все объекты и элементы сериализуемы, поэтому не работает во всех случаях. Если все объекты сериализуемы, то это очень эффективный способ глубокого копирования объекта. Это может быть сделано следующим образом:

public class SerializationHelper { 
public static byte[] serialize(Object object) throws IOException { 
    ByteArrayOutputStream os = new ByteArrayOutputStream(); 
    new ObjectOutputStream(os).writeObject(object); 
    return os.toByteArray(); 
} 

@SuppressWarnings("unchecked") 
public static <T> T deSerialize(byte[] array) throws IOException, ClassNotFoundException { 
    return (T)new ObjectInputStream(new ByteArrayInputStream(array)).readObject(); 
} 

@SuppressWarnings("unchecked") 
public static <T> T clone(T object) { 
    try { 
     return (T)deSerialize(serialize(object)); 
    } catch (Exception e) { 
     throw new RuntimeException(e); 
    } 
} 
0

Лучший подход зависит от ситуации и ваших потребностей - каковы ваши ограничения производительности - если вам нужна глубокая/мелкая копия и насколько хорошо ваши классы поддерживают сериализацию.

Конструкторы копирования и фабричные методы

Есть еще действующий вариант. Когда вам нужна глубокая копия, и вы работаете со сложными объектами с зависимостями, их может быть очень сложно написать. Гораздо быстрее, чем сериализация/десериализация.

сериализации/десериализации

Может быть легко осуществить, и вы можете копировать сложные объекты с минимальными усилиями глубоких копий. Однако вам нужны все объекты, которые могут быть сериализуемыми, а поля переходных процессов не будут скопированы. Кроме того, это дороже, чем конструкторы копирования и другие варианты.

Вам не нужно писать логику сериализации/десериализации, как уже есть сторонние библиотеки для этого, такие как:

Apache Commons Serialization Utils - Вы можете просто позвонить SerializationUtils.clone()

Отражение

Существуют также различные сторонние инструменты, использующие отражение для клонирования. Вы можете использовать Apache Commons BeanUtils, если вам достаточно мелкой копии, и вы следуете за соглашением JavaBeans. Просто позвоните BeanUtils.cloneBean().

Если вам нужно глубокое копирование вместо этого, вы можете использовать, например:

Я написал blog post сравнивая подходы выше, где вы можете найти бит более подробно.