Почему клонируемый интерфейс Java не является универсальным? - PullRequest
13 голосов
/ 23 декабря 2008

Java 5 представила дженерики, и они были добавлены ко многим интерфейсам в пакете java.lang. Однако Cloneable не получил дженерики. Интересно почему?


Редактировать: В ответ на ответы @Jon и @litb и комментарий @Earwicker я подумал, Cloneable может быть:

public interface Cloneable<T> {
    public T clone();
}

Здесь T clone(); переопределяет Object.clone(), придавая ему ковариантный тип. Я считаю, что это все равно будет обратно совместимо и увеличит безопасность типов. Так почему бы и нет?


Редактировать 2: Как видно из ответов (и комментариев) ниже, предложенный выше интерфейс нарушит обратную совместимость. Поскольку Object.clone() - это protected, перезапись его в интерфейсе вынудит всех разработчиков предоставить реализацию public, которую разработчики классов могут не захотеть (т.е. они могут оставить ее protected).

Ответы [ 5 ]

20 голосов
/ 23 декабря 2008

Интерфейс Cloneable не содержит членов. Какой смысл делать его родовым?

(Если бы Cloneable содержал метод clone (), это имело бы смысл - но это объявлено в java.lang.Object.)

РЕДАКТИРОВАТЬ: clone () находится в java.lang.Object, поскольку у него есть реализация (которая делает полевое копирование). Лучшим вариантом было бы иметь что-то вроде * .NET 100% * MemberwiseClone () в качестве защищенного метода в Object, а затем открытый метод clone () внутри самого интерфейса. Я не знаю, почему этот дизайн не был выбран.

(В .NET ICloneable не является универсальным, потому что он существовал до генериков - различная природа универсальных .NET предотвращает превращение ранее не универсального типа в универсальный.)

Однако как в Java, так и в .NET «нормальный» API-интерфейс клонирования обычно считается плохим, поскольку в нем ничего не говорится о том, какую глубину клонирования следует выполнять.

9 голосов
/ 24 июня 2011

Если бы Cloneable было Cloneable<T>, то было бы невозможно сделать это:

class A extends B implements Cloneable<A>

class B implements Cloneable<B>

Нельзя реализовать один и тот же интерфейс с разными параметрами, а класс A реализует Cloneable<A> и Cloneable<B>.

.
6 голосов
/ 23 декабря 2008

java.lang.Cloneable является интерфейсом маркера. Это исключительно для этой цели, так что Object.clone может выдать исключение, чтобы указать, что класс не поддерживает клонирование, используя, например,

if(!(this instanceof Cloneable))
    throw...;

Из документации:

Метод клонирования для класса Object выполняет определенную операцию клонирования. Во-первых, если класс этого объекта не реализует интерфейс Клонируемый, а затем Исключение CloneNotSupportedException.

У него нет методов. Создание общего не будет никакого смысла.

3 голосов
/ 24 декабря 2008

Это не относится к вашему теоретическому вопросу, но обрабатывает практический случай:

Java 5 имеет ковариантные возвращаемые значения и позволяет расширить доступ к методам. Таким образом, вы можете изменить подпись для clone () соответствующим образом в подклассах.

public class MyClass implements Cloneable {
    public MyClass clone(){ /* do the right stuff */ }
}

MyClass.clone() - это корректное переопределение Object.clone(), и вам не нужно будет писать приведения.

1 голос
/ 23 декабря 2008

В качестве полуотносительного мысленного вопроса: будет ли полезным создание интерфейса (назовите его ReallyCloneable), который выставляет clone () в качестве открытого члена?

Я утверждаю, что нет, не будет. Клонируемость тесно связана с реализацией конкретного класса. Я не могу вспомнить ни одного случая использования, когда я могу сказать: «У меня есть произвольный объект, и я хочу его копию». Непосредственный вопрос: зачем вам эта копия?

И типичный ответ таков, что вы можете изменить копию, не затрагивая оригинал. Однако, чтобы сделать это, вам нужно знать, какой тип объекта вы держите, иначе как вы узнаете, что вызывать, чтобы изменить его? И если вы это знаете, вы узнаете, предоставляет ли он публичный метод clone ().

Но что, если вы программируете для интерфейса, такого как List? Интеллектуальное (рекурсивное) клонирование (по сравнению с копированием данных объекта на уровне байтов) было бы невероятно полезным в среде Collections. Но могут быть коллекции (например, те, которые поддерживаются базой данных), которые не могут поддерживать такую ​​операцию, поэтому вы не можете требовать, чтобы List выставлял открытый клон (). Что побуждает вас к созданию собственной конкретной реализации List для копирования содержимого исходного List.

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