Когда имеет смысл, чтобы объект Java был сериализуемым, но не клонируемым? - PullRequest
7 голосов
/ 24 января 2010

Если класс Java реализует интерфейс Serializable, но не имеет общедоступного метода clone(), обычно можно создать глубокую копию, подобную этой:

class CloneHelper {
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T clone(T obj) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            oos.close();
            byte[] bytes = baos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            T copy = (T) ois.readObject();
            ois.close();
            return copy;
        } catch (ClassNotFoundException ex) {
            // Shouldn't happen
            throw new Error(ex);
        } catch (IOException ex) {
            // Probably a bug in T's custom serialization methods
            throw new RuntimeException(ex);
        }
    }
}

Я часто сталкиваюсь со сторонними библиотечными классами, такими как этот, и прибегаю к взломам, подобным приведенному выше. Я даже увеличил ObjectOutputStream, чтобы сделать копию меньше. Это никогда не вызывало серьезных проблем, кроме неэффективности (медленное кодирование / декодирование и временные графы сериализации могут занимать много памяти.)

И если использовать эту технику небезопасно, класс, вероятно, не должен был быть объявлен Serializable.

Итак, что я хотел бы знать, если ваш класс Serializable, что может помешать вам определить открытый метод clone() (с использованием интерфейса Cloneable или конструктора копирования?)


Похожие: Скопировать объект на Java

Ответы [ 7 ]

5 голосов
/ 24 января 2010

Я бы предпочел использовать конструктор копирования, а не использовать вышеуказанный механизм. Вы можете более точно определить, что должно быть глубоко или поверхностно скопировано, и сделать копирование объекта отличным от сериализации объекта. Конструктор копирования может (например) разрешить двум объектам совместно использовать ссылку на главный объект, тогда как это может не подходить для объекта, сериализованного и переданного по сети.

Обратите внимание, что метод Cloneable в настоящее время считается сломленным. См. эту статью с Джошуа Блохом для получения дополнительной информации. В частности, у него нет clone() метода!

4 голосов
/ 24 января 2010

Замечание Брайана о Cloneable очень хорошо, но даже если Cloneable работал правильно, все еще есть случаи, когда вы хотите, чтобы объект был сериализуемым, но не клонируемым.

Если объект имеет уникальную идентичность вне области процесса, например представление в базе данных записи в памяти, вы не хотите, чтобы он был клонируемым, поскольку это эквивалентно созданию новой записи с идентичными атрибутами, включая связанные с идентичностью атрибуты, такие как ключ базы данных, что почти никогда не бывает правильным. В то же время у вас может быть система, разбитая на несколько процессов для стабильности или по другим причинам, поэтому у вас может быть один процесс, говорящий с базой данных и генерирующий эти объекты «ENTITY» (см. «Проект на основе домена» Эрика Эванса для получения дополнительной информации). информация о поддержании согласованности идентификатора объекта в приложении с поддержкой данных), но отдельный процесс может использовать эти объекты для выполнения операций бизнес-логики. Объект сущности должен быть сериализуемым, чтобы его можно было передавать из одного процесса в другой.

2 голосов
/ 24 января 2010

Я думаю, что интерфейсы Serializable и Cloneable следует использовать для совершенно разных целей. И если у вас есть сложный класс, то реализовать каждый из них не так просто. Так что в общем случае это зависит от целей.

1 голос
/ 25 января 2010

Одной из самых больших проблем с Serializable является то, что их нельзя легко сделать неизменяемыми. Сериализация вынуждает вас идти на компромисс.

Я бы соблазнился создать конструкторы копирования по графу объектов. Это немного более грубая работа.

1 голос
/ 24 января 2010

Ну, вы говорите, что механизм сериализации - это один из способов косвенного клонирования объектов. Это, конечно, не его основная функция. Обычно он используется для того, чтобы программы могли передавать объекты по сети или сохранять и затем читать их. Вы можете ожидать, что объект будет использоваться таким образом, и реализовать Serializable, не ожидая, что код будет клонировать объекты локально, и не реализует Cloneable.

Тот факт, что код работает вокруг этого посредством сериализации, предполагает, что код использует объект способом, который автор не намеревался, что может быть либо «ошибкой» автора, либо вызывающей стороны, но это не означает, что общие Сериализуемый и Клонируемый идут вместе.

Отдельно я не уверен, что clone () "сломан" настолько сложно, насколько правильно реализовать. ИМХО конструктор копирования более естественен для использования и получен правильно.

0 голосов
/ 22 октября 2011

Я просто подумал о другом случае - когда это перечисление .

Или, в более общем случае, когда ваш класс реализует readResolve. Это означает, что объект, который вы получаете от readObject, не тот, который был прочитан из потока, и, следовательно, это не обязательно копия объекта, который был первоначально записан в поток.

0 голосов
/ 24 января 2010

Это кажется мне довольно опасным, поскольку существует ряд ловушек при сериализации (хотя большинство из них маловероятны, я все же хотел бы проверить их на предмет сериализации объектов в сторонних библиотеках). Вряд ли это будет распространенной проблемой, но возможно иметь объект с изменчивой переменной как часть его состояния, который может быть частью операции клонирования (не то, что это хороший дизайн, просто это возможно), и такой поле не будет скопировано в процессе сериализации / десериализации. Еще одна проблема, которая приходит на ум - это перечисления, константы и возможность получения нескольких копий таких вещей, если вы не имеете дело с ними во время десериализации.

Опять же, крайние случаи, но то, что вы хотели бы остерегаться.

...