Чтение онлайн

на главную - закладки

Жанры

Программирование на Java

Вязовик Н.А.

Шрифт:

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

Обратите внимание, что сам класс Object не реализует интерфейс Cloneable, а потому попытка вызова new Object.clone будет приводить к ошибке. Метод clone предназначен скорее для использования в наследниках,

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

* модификатор доступа расширен до public ;

* удалено предупреждение об ошибке CloneNotSupportedException ;

* результирующий объект может быть модифицирован любым способом, на усмотрение разработчика.

Напомним, что все массивы реализуют интерфейс Cloneable и, таким образом, доступны для клонирования.

Важно помнить, что все поля клонированного объекта приравниваются, их значения никогда не клонируются. Рассмотрим пример:

public class Test implements Cloneable {

Point p;

int height;

public Test(int x, int y, int z) {

p=new Point(x, y);

height=z;

}

public static void main(String s[]) {

Test t1=new Test(1, 2, 3), t2=null;

try {

t2=(Test) t1.clone;

}

catch (CloneNotSupportedException e) {

}

t1.p.x=-1;

t1.height=-1;

System.out.println("t2.p.x=" + t2.p.x + ", t2.height=" + t2.height);

}

}

Результатом работы программы будет:

t2.p.x=-1, t2.height=3

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

А вот ссылочное поле было скопировано по ссылке, оба объекта ссылаются на один и тот же экземпляр класса Point. Поэтому изменения, происходящие с исходным объектом, сказываются на клонированном.

Этого можно избежать, если переопределить метод clone в классе Test.

public Object clone {

Test clone=null; try {

clone=(Test) super.clone;

}

catch (CloneNotSupportedException e) {

throw new InternalError(e.getMessage);

}

clone.p=(Point)this.p.clone;

return clone;

}

Обратите внимание, что результат метода Object.clone приходится явно приводить к типу Test, хотя его реализация гарантирует, что клонированный объект будет порожден именно от этого класса. Однако тип возвращаемого значения в данном методе для универсальности объявлен как Object, поэтому явное сужение необходимо.

Теперь метод main можно упростить:

public static void main(String s[]) {

Test t1=new Test(1, 2, 3);

Test t2=(Test) t1.clone;

t1.p.x=-1; t1.height=-1;

System.out.println("t2.p.x=" + t2.p.x +

", t2.height=" + t2.height);

}

Результатом

будет:

t2.p.x=1, t2.height=3

То есть теперь все поля исходного и клонированного объектов стали независимыми.

Реализация такого "неглубокого" клонирования в методе Object.clone необходима, так как в противном случае клонирование второстепенного объекта могло бы привести к огромным затратам ресурсов, ведь этот объект может содержать ссылки на более значимые объекты, а те при клонировании также начали бы копировать свои поля, и так далее. Кроме того, типом поля клонируемого объекта может быть класс, не реализующий Cloneable, что приводило бы к дополнительным проблемам. Как показано в примере, при необходимости дополнительное копирование можно добавить самостоятельно.

Клонирование массивов

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

Рассмотрим пример:

int a[]=

{1, 2, 3};

int b[]=(int[])a.clone;

a[0]=0;

System.out.println(b[0]);

Результатом будет единица, что вполне очевидно, так как весь массив представлен одним объектом, который не будет зависеть от своей копии. Усложняем пример:

int a[][]= {{1, 2}, {3}};

int b[][]=(int[][]) a.clone;

if (...) {

// первый вариант:

a[0]=new int[] {0};

System.out.println(b[0][0]);

} else {

// второй вариант:

a[0][0]=0;

System.out.println(b[0][0]);

}

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

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

Во втором случае модифицируется существующий массив, что скажется на обоих двухмерных массивах. На консоли появится 0.

Обратите внимание, что если из примера убрать условие if-else, так, чтобы отрабатывал первый вариант, а затем второй, то результатом будет опять 1, поскольку в части второго варианта модифицироваться будет уже новый массив, порожденный в части первого варианта.

Поделиться:
Популярные книги

Ловите конский топот. Том 1. Исхода нет, есть только выходы...

Звягинцев Василий Дмитриевич
15. Одиссей покидает Итаку
Фантастика:
альтернативная история
8.24
рейтинг книги
Ловите конский топот. Том 1. Исхода нет, есть только выходы...

Играть... в тебя

Зайцева Мария
3. Звериные повадки Симоновых
Любовные романы:
современные любовные романы
5.25
рейтинг книги
Играть... в тебя

Сексуальная жизнь мужчины. Книга 1

Еникеева Диля Дэрдовна
Дом и Семья:
образовательная литература
здоровье и красота
7.00
рейтинг книги
Сексуальная жизнь мужчины. Книга 1

Зарево горящих деревень

Инин Дмитрий
4. Негодяй Аллара
Фантастика:
фэнтези
рпг
5.00
рейтинг книги
Зарево горящих деревень

Рыцарь Империи

Буревой Андрей
3. Одержимый
Фантастика:
фэнтези
9.39
рейтинг книги
Рыцарь Империи

Больше чем Герой! Том 9

Довыдовский Кирилл Сергеевич
9. Путешествие Героя
Фантастика:
героическая фантастика
юмористическое фэнтези
городское фэнтези
рпг
5.00
рейтинг книги
Больше чем Герой! Том 9

"Фантастика 2023-121". Компиляция. Книги 1-25

Башибузук Александр
Фантастика 2023. Компиляция
Фантастика:
фэнтези
боевая фантастика
5.00
рейтинг книги
Фантастика 2023-121. Компиляция. Книги 1-25

Люсьен Левен (Красное и белое)

Стендаль Фредерик
Проза:
классическая проза
7.00
рейтинг книги
Люсьен Левен (Красное и белое)

Бояръ-Аниме. Газлайтер. Том 35

Володин Григорий Григорьевич
35. История Телепата
Фантастика:
аниме
боевая фантастика
фэнтези
6.40
рейтинг книги
Бояръ-Аниме. Газлайтер. Том 35

Миры Филипа Фармера. Том 4. Больше чем огонь. Мир одного дня

Фармер Филип Хосе
Фантастика:
научная фантастика
5.00
рейтинг книги
Миры Филипа Фармера. Том 4. Больше чем огонь. Мир одного дня

Гримуар темного лорда IV

Грехов Тимофей
4. Гримуар темного лорда
Фантастика:
фэнтези
боевая фантастика
попаданцы
аниме
6.00
рейтинг книги
Гримуар темного лорда IV

Первый Предтеча. Трилогия

Тарс Элиан
Первый Предтеча
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Первый Предтеча. Трилогия

Спецоперации. Лубянка и Кремль 1930–1950 годы

Судоплатов Павел Анатольевич
Документальная литература:
биографии и мемуары
5.00
рейтинг книги
Спецоперации. Лубянка и Кремль 1930–1950 годы

Арканарский вор (Трилогия)

Шелонин Олег Александрович
Арканарский вор
Фантастика:
юмористическая фантастика
9.00
рейтинг книги
Арканарский вор (Трилогия)