Cloneable # clone method ненужное приведение - PullRequest
2 голосов
/ 10 июля 2020
class MyCls implements Cloneable {
  @Override
  protected MyCls clone() throws CloneNotSupportedException {
    return new MyCls(//...
  }
}

Приведенный выше код не вызывает никаких проблем. Так почему же CopyOnWriteArrayList#clone возвращает Object вместо CopyOnWriteArrayList? Компилятор плачет при обратном приведении Object к желаемому типу. В чем все-таки может быть причина такого дизайнерского решения? Я вижу, что этот шаблон повторяется по всей библиотеке.

Ральф предположил, что следующий код действителен вместо кода выше:

@Override MyCls clone() throws CloneNotSupportedException { 
  MyCls clone = (MyCls)super.clone();
  clone.x = this.x; //or what ever to do return clone
  // ...
}

Вопрос остается прежним . Почему CopyOnWriteArrayList#clone возвращает Object вместо себя?

1 Ответ

6 голосов
/ 10 июля 2020

Ваш вопрос основан на ковариантных типах возврата , то есть на возможности переопределить метод с более конкретным c типом возврата.

Эта функция не всегда существовала в Java. Если быть более точным, он был введен в Java 5, той же версии, которая также представила инструменты параллелизма, включая CopyOnWriteArrayList.

Но это не значит, что сначала было разработано обновление языка, а классы - потом. Классы прошли процесс разработки, который начался до Java 5 и более ранних версий, и черновики можно было загрузить из http://gee.cs.oswego.edu/dl/concurrency-interest/

Таким образом, более ранние версии должны были объявлять тот же тип возвращаемого значения, что и замещаемый метод, и когда они были выпущены вместе с Java 5, никто вовремя не подумал об изменении метода для использования ковариантных возвращаемых типов. И, видимо, до сих пор никто из ответственных за это не учел. Это может быть недостаточно важно.

Это не уникальная ситуация.

API NIO Buffer был представлен в JDK 1.4, на одну версию раньше, чем ковариантные возвращаемые типы были возможны, и это длилось до Java 9, прежде чем были добавлены переопределения с более конкретными c возвращаемыми типами (например, ByteBuffer.position(int), limit(int) или clear() ; сравните с версией Java 8 , имеющей только унаследованные версии, которые препятствовали плавному использованию API).

Но помните, что изменение метода для использования ковариантных возвращаемых типов после того, как класс был опубликован, может создавать проблемы совместимости при компиляции кода под более новыми версиями JDK, чем предполагается. Решение, опция --release , также было представлено в JDK 9.

...