Почему перечисления Java не поддаются клонированию?

StackOverflow https://stackoverflow.com/questions/1803503

  •  05-07-2019
  •  | 
  •  

Вопрос

Уже слишком поздно менять вопрос, но более точным было бы спросить "Почему clone () не допускает одиночек?".A copy() метод был бы более удобным.


Есть ли какая-либо причина, по которой перечисления в Java не могут быть клонированы?

В руководстве говорится , что

Это гарантирует, что перечисления никогда не будут клонированы, что необходимо для сохранения их статуса "singleton".

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

Кто - то может возразить , что

Общее намерение [clone()] состоит в том, что для любого объекта x выражение: x.clone() != x будет правдой, [...]

Но для одиночек, наоборот, я хочу x.clone() == x чтобы быть правдой.Если бы был возвращен сам экземпляр, то шаблон singleton был бы прозрачен для ссылающихся объектов.

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

Это было полезно?

Решение

Но для одиночек, наоборот, я хочу x.clone() == x чтобы быть правдой.

Ты возможно, вы захотите, но я думаю, это странно, что следующий код сломается:

interface Foo extends Cloneable { public int getX(); public void setX(int x);  }
enum FooSingleton implements Foo { 
    INSTANCE; 
    private int x;
    public int getX(){ return x; }
    public void setX(int x){ this.x = x; }
}
class FooClass implements Foo { 
    private int x;
    public int getX(){ return x; }
    public void setX(int x){ this.x = x; }
}

boolean omg(Foo f){
    Foo c = f.clone();
    c.setX(c.getX() + 1);
    return c.getX() != f.getX();   
}
assert omg(new FooClass());        // OK
assert omg(FooSingleton.INSTANCE); // WTF?

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

С другой стороны, я могу отчасти согласиться с тем, что имело бы смысл для операций клонирования просто return this для неизменяемых объектов перечисления действительно должны быть неизменяемыми.Теперь, когда контракт на clone() когда это было написано, они, очевидно, не думали о неизменяемых, или им не нужен был особый случай для концепции, которая не поддерживается языком (т. Е. Неизменяемые типы).

И вот, clone() это то, что есть, и вы не можете пойти и изменить что-то, что существует со времен Java 1.0.Я совершенно уверен, что где-то там есть код, который полностью полагается на clone() возвращает новый, отличный объект, возможно, в качестве ключа для IdentityHashMap или что-то в этом роде.

Другие советы

Какова цель клонирования синглтона, если x.clone() == x?Разве ты не можешь просто использовать x прямо сейчас.

Строго говоря, если вы хотите что-то клонировать и обеспечивать соблюдение x.clone() == x, единственным объектом , который может быть результатом клонирования , является x сам по себе:

def clone() {
  return this;
}

Что может ввести в заблуждение...


Если вы что-то разрабатываете и основываетесь на clone() что касается дифференциации, то, ИМХО, вы делаете это неправильно...

Если ваш метод клонирования возвращает this экземпляр, а не отдельный объект, тогда это не клон, не так ли?

Джавадок говорит:

По соглашению, объект, возвращаемый этим методом, должен быть независимым от этого объекта (который клонируется).

Предполагается, что перечисления не должны быть клонированы, потому что предполагается, что всегда должен быть только один экземпляр каждого значения.

Редактировать: В ответ на следующий комментарий:

Это именно то, что я критикую.Почему не вернуть тот же экземпляр, если другого быть не может ?

Потому что на самом деле это не имеет смысла.Если это один и тот же объект, то это не клон.Javadocs также говорят:

Общее намерение состоит в том, что для любого объекта x выражение:

x.clone() != x
будет истинным, и что выражение:
x.clone().getClass() == x.getClass()
будет верно, но это не абсолютные требования.

Таким образом, намерение состоит в том, чтобы clone() метод для возврата отдельного объекта.К сожалению, там говорится, что это не абсолютное требование, что делает ваше предложение действительным, но я все еще думаю, что это неразумно, потому что бесполезно иметь метод clone, который возвращает this.Это могло бы даже вызвать проблемы, если бы вы делали что-то сомнительное, например, имели изменяемое состояние в ваших константах enum или синхронизировались с ними.Поведение такого кода будет отличаться в зависимости от того, выполнил ли метод clone правильное клонирование или просто вернул this.

Вы на самом деле не объясняете, почему вы хотите рассматривать перечисления как Cloneable когда они по своей сути не поддаются клонированию.Желание иметь метод клонирования, который не подчиняется принятым соглашениям, похоже на взлом для решения какой-то более фундаментальной проблемы с вашим подходом.

Я предполагаю, что они не хотели рассматривать синглтоны как особый случай, когда clone() было указано.Это усложнило бы спецификацию.Так что теперь разработчикам библиотек приходится относиться к ним как к особому случаю, но для остальных из нас приятно, что мы можем доверять этому x.clone() != x.

Ваш собственный ответ на ваш вопрос - самый лучший.В общем, люди ожидают clone() чтобы вернуть другой объект.Семантика Cloneable само по себе это имеет больше смысла.("Объект можно клонировать ... о, я должен иметь возможность делать копии".) Я не могу навскидку представить ситуацию, когда это имеет значение, но это было предполагаемое семантическое значение Cloneable.

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

Но для одиночек, наоборот, я хочу x.clone() == x чтобы быть правдой.

Нет, это был бы не клон.Итак, для одиночек вам нужно это:

public Object clone() throws CloneNotSupportedException {
  throw new CloneNotSupportedException(); 
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top