Как правильно переопределить метод клона?

Я должен реализовать глубокий клон в одном из моих объектов, который не имеет никакого суперкласса.

Что лучший способ состоит в том, чтобы обработать проверенное CloneNotSupportedException брошенный суперклассом (который является Object)?

Коллега советовал мне обрабатывать его следующий путь:

@Override
public MyObject clone()
{
    MyObject foo;
    try
    {
        foo = (MyObject) super.clone();
    }
    catch (CloneNotSupportedException e)
    {
        throw new Error();
    }

    // Deep clone member fields here

    return foo;
}

Это походит на хорошее решение меня, но я хотел вывести его сообществу StackOverflow, чтобы видеть, существует ли какое-либо другое понимание, которое я могу включать.Спасибо!

109
задан MC Emperor 17 January 2013 в 13:12
поделиться

6 ответов

В списке можно использовать\colorbox и символ escape:

Добавьте в преамбулу

  \usepackage{color}

  \definecolor{light-gray}{gray}{0.80}

, затем используйте его следующим образом:

  \begin{lstlisting}[escapechar=!]
  def mult(m: Matrix[Int], n: Matrix[Int]) {
    val p = !\colorbox{light-gray}{new MatrixInt}!(m.rows, n.cols)
  }
  \end{lstlisting}
-121--1360192-

Используйте setOnClickListener () для регистрации прослушивателя, который затем проверяет,

-121--4605228-

Обязательно ли использовать клон ? Большинство людей согласны с тем, что клон Java сломан.

Джош Блох на дизайн - копировать конструктор против клонирования

Если вы прочитали пункт о клонировании в моей книге, особенно если вы читаете между строк, вы будете знать, что я думаю, что клон глубоко сломан. [...] Обидно, что Клонируемый сломан, но так бывает.

Подробнее об этой теме можно прочитать в его книге Effective Java 2nd Edition, Пункт 11: Override clone judicicially . Вместо этого он рекомендует использовать конструктор копий или завод по копированию.

Далее он написал страницы о том, как, если вы чувствуете, что должны, вы должны реализовать клон . Но он закрылся этим:

Действительно ли все эти сложности необходимы? Редко. При расширении класса, реализующего Cloneable , у вас нет другого выбора, кроме как реализовать хорошо работающий метод clone . В противном случае лучше предоставить альтернативные средства копирования объектов или просто не предоставлять возможности .

Акцент был на нем, а не на моем.


Поскольку вы дали понять, что у вас мало выбора, кроме как реализовать клон , вот что вы можете сделать в этом случае: убедитесь, что MyObject расширяет java.lang.Object реализует java.lang.Cloneable . Если это так, вы можете гарантировать, что НИКОГДА не поймаете CloneNotSupportedException . Ввод AssertureError , как некоторые предлагали, представляется разумным, но можно также добавить комментарий, объясняющий, почему блок catch никогда не будет введен в данном конкретном случае .


Также, как и другие, можно реализовать клон без вызова super.clone .

120
ответ дан 24 November 2019 в 03:23
поделиться

Иногда проще реализовать конструктор копирования:

public MyObject (MyObject toClone) {
}

Это избавляет вас от необходимости обрабатывать CloneNotSupportedException , работает с ] final , и вам не нужно беспокоиться о возвращаемом типе.

55
ответ дан 24 November 2019 в 03:23
поделиться

Существует два случая, в которых будет создано CloneNotSupportedException :

  1. Клонируемый класс не реализован Клонируемый (при условии, что фактическое клонирование в конечном итоге отложит метод клонирования объекта ). Если класс, записывающий этот метод в implements Cloneable , этого никогда не произойдет (так как любые подклассы наследуют его соответствующим образом).
  2. Исключение явно вызывается реализацией - это рекомендуемый способ предотвратить клонирование в подклассе, когда суперкласс имеет значение Клонируемый .

Последний случай не может возникнуть в вашем классе (так как вы вызываете непосредственно метод superclass 'в блоке try , даже если вызывается из подкласса, вызывающего super.clone () ), и первый не должен, так как ваш класс явно должен реализовывать Cloneable .

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


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

Edit : Хотя в целом я должен отметить, что да, clone () действительно трудно реализовать правильно и трудно для вызывающих, чтобы знать, будет ли возвращаемое значение то, что они хотят, вдвойне, когда вы считаете глубокий против мелкого клонов. Часто лучше просто полностью избегать всего этого и использовать другой механизм.

-121--709712-

Я бы просто использовал данные в «длинном» формате.

Например.

> d1 <- data.frame(id=1:3, num_words=c(2,1,4), phrase=c("hello world", "greetings", "take me to your leader"))
> d2 <- data.frame(id=c(rep(1,2), rep(2,1), rep(3,5)), token_length=c(5,5,9,4,2,2,4,6))
> d2$tokenid <- with(d2, ave(token_length, id, FUN=seq_along))
> d <- merge(d1,d2)
> subset(d, nchar(phrase) > 10)
  id num_words                 phrase token_length tokenid
1  1         2            hello world            5       1
2  1         2            hello world            5       2
4  3         4 take me to your leader            4       1
5  3         4 take me to your leader            2       2
6  3         4 take me to your leader            2       3
7  3         4 take me to your leader            4       4
8  3         4 take me to your leader            6       5
> with(d, tapply(token_length, id, mean))
  1   2   3 
5.0 9.0 3.6 

Как только данные находятся в длинном формате, можно использовать sqldf или plyr для извлечения из них желаемого.

-121--3338901-

Ваш код работает довольно близко к «каноническому» способу его написания. Я бы выбросил AssertureError в улов, хотя. Он сигнализирует, что эта линия никогда не должна быть достигнута.

catch (CloneNotSupportedException e) {
    throw new AssertionError(e);
}
11
ответ дан 24 November 2019 в 03:23
поделиться

Вы можете реализовать конструкторы защищенного копирования следующим образом:

/* This is a protected copy constructor for exclusive use by .clone() */
protected MyObject(MyObject that) {
    this.myFirstMember = that.getMyFirstMember(); //To clone primitive data
    this.mySecondMember = that.getMySecondMember().clone(); //To clone complex objects
    // etc
}

public MyObject clone() {
    return new MyObject(this);
}
3
ответ дан 24 November 2019 в 03:23
поделиться

Есть два случая, в которых CloneNotSupportedException будет сгенерировано:

  1. Клонируемый класс не реализован Cloneable (при условии, что фактическое клонирование в конечном итоге относится к Метод клонирования объекта ). Если класс, в котором вы пишете этот метод, реализует Cloneable , этого никогда не произойдет (поскольку любые подклассы унаследуют его соответствующим образом).
  2. Исключение явно выбрасывается реализацией - это рекомендуемый способ предотвратить клонирование в подклассе, когда суперкласс Cloneable .

Последний случай не может иметь место в вашем классе (поскольку вы напрямую вызываете метод суперкласса в блоке try , даже если вызывается из подкласса, вызывающего super.clone () ]), а в первом случае не следует, поскольку ваш класс явно должен реализовывать Cloneable .

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


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

Правка : Хотя в целом я должен отметить, что да, clone () действительно сложно реализовать правильно и вызывающим абонентам сложно узнать, будет ли возвращаемое значение таким, каким они хотят, вдвойне. когда вы рассматриваете глубокие и мелкие клоны. Часто лучше полностью избегать всего этого и использовать другой механизм.

9
ответ дан 24 November 2019 в 03:23
поделиться

Используйте сериализацию для создания глубоких копий. Это не самое быстрое решение, но оно не зависит от типа.

5
ответ дан 24 November 2019 в 03:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: