Главная страница

Ответы на вопросы по ревью 4. Java io. Ключевым понятием здесь является понятие потока


Скачать 1.93 Mb.
НазваниеJava io. Ключевым понятием здесь является понятие потока
Дата03.07.2022
Размер1.93 Mb.
Формат файлаdoc
Имя файлаОтветы на вопросы по ревью 4.doc
ТипДокументы
#623608
страница29 из 39
1   ...   25   26   27   28   29   30   31   32   ...   39

1. Использование Object.clone() метод


Классы, которым нужна функция копирования, могут использовать Object.clone() метод, который создает и возвращает копию объекта. Прототип Object.clone() является

1

protected Object clone() throws CloneNotSupportedException;

В качестве возвращаемого типа Object.clone() является Object, приведение типов необходимо для присвоения возвращаемой ссылки Object ссылке на объект.

Все задействованные классы должны реализовывать Клонируемый интерфейс для указания Object.clone() метод о том, что для этого метода разрешено создавать полевые копии экземпляров этого класса. Вызов метода clone объекта для экземпляра, который не реализует Cloneable интерфейс приводит к CloneNotSupportedException.

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

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

Минусы:

1. Object.clone() не будет работать с интерфейсами и абстрактными классами.

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

Например, нельзя вызвать clone() в ссылке на карту в Java, потому что карта не указывает общедоступного clone() метод. Только реализации карты, такие как HashMap а также LinkedHashMap имеют clone() методы, но носить с собой тип класса объекта не рекомендуется, и это противоречит принципу «программа для интерфейса, а не для реализации».

 
2. Реализация по умолчанию Object.clone() метод возвращает Неглубокое копирование.

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

Поверхностное клонирование



 
Следующая программа демонстрирует использование Object.clone() метод, используя его реализацию по умолчанию, которая возвращает поверхностную копию. Мы рассмотрим глубокое копирование с помощью clone() метод в следующем разделе.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

import java.util.Arrays;

import java.util.HashMap;

import java.util.HashSet;

import java.util.Set;

import java.util.Map;

 

// `Subject` также должен реализовать `Cloneable`!!

class Subject implements Cloneable

{

    private Set subjects;

 

    public Subject()

    {

        subjects = new HashSet<>(

                Arrays.asList("Maths", "Science", "English", "History")

        );

    }

 

    @Override

    public Object clone() throws CloneNotSupportedException {

        // вызовите `super.clone()`, чтобы получить ссылку на клонированный объект

        return super.clone();

    }

 

    @Override

    public String toString() {

        return subjects.toString();

    }

 

    public Set getSubjects() {

        return subjects;

    }

}

 

// Обратите внимание, что `Student` реализует интерфейс `Cloneable`

class Student implements Cloneable

{

    private String name;        // неизменяемое поле

    private int age;            // примитивное поле

 

    private Subject subjects;

    private Map map;

 

    public Student(String name, int age)

    {

        this.name = name;

        this.age = age;

 

        map = new HashMap() {{

            put(name, age);

        }};

 

        subjects = new Subject();

    }

 

    @Override

    public String toString()

    {

        return Arrays.asList(name, String.valueOf(age),

                subjects.toString()).toString();

    }

 

    @Override

    public Object clone() throws CloneNotSupportedException {

        // вызовите `super.clone()`, чтобы получить ссылку на клонированный объект

        return super.clone();

    }

 

    public Set getSubjects() { return subjects.getSubjects(); }

    public Map getMap() { return map; }

 

    // включаем оставшиеся геттеры и сеттеры

}

 

// Демонстрация поверхностного копирования объектов с помощью метода `clone()`

class Main

{

    // Вспомогательный метод для сравнения двух объектов. Он печатает мелкую копию

    // если оба объекта имеют один и тот же объект; в противном случае он печатает глубокую копию

    public static void compare(Object ob1, Object ob2)

    {

        if (ob1 == ob2) {

            System.out.println("Shallow Copy");

        }

        else {

            System.out.println("Deep Copy");

        }

    };

 

    public static void main(String[] args)

    {

        Student student = new Student("Jon Snow", 22);

 

        Student clone = null;

        try {

            clone = (Student) student.clone();

            System.out.println("Cloned Object: " + clone + '\n');

        } catch (CloneNotSupportedException ex) {

            ex.printStackTrace();

        }

 

        compare(student.getSubjects(), clone.getSubjects());

        compare(student.getMap(), clone.getMap());

 

        // любое изменение, внесенное в карту клона, отразится на карте ученика

        clone.getMap().put("John Cena", 40);

        System.out.println(student.getMap());

    }

}

Скачать  Выполнить код

результат:

Cloned Object: [Jon Snow, 22, [Maths, English, Science, History]]
 
Shallow Copy
Shallow Copy
{Jon Snow=22, John Cena=40}

Глубокое клонирование

Если класс содержит только примитивы и поля Immutable, поверхностная копия работает нормально. Но любые изменяемые поля, такие как коллекции и массивы, будут совместно использоваться оригиналом и копией, поскольку Object.clone() возвращает точную копию исходного объекта.

Для глубокого клонирования, если класс содержит какие-либо ссылки на объекты, clone() Метод должен выполнить все необходимые модификации объекта, полученного от суперкласса, прежде чем вернуться к вызывающей стороне. т.е., clone() метод должен изменять изменяемые поля объектов, возвращаемых super.clone(). Один из способов сделать это — вызвать clone() метод на изменяемых полях.



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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

import java.util.Arrays;

import java.util.HashMap;

import java.util.HashSet;

import java.util.Set;

import java.util.Map;

 

// `Subject` также должен реализовать `Cloneable`!!

class Subject implements Cloneable

{

    private Set subjects;

 

    public Subject()

    {

        subjects = new HashSet<>(

                Arrays.asList("Maths", "Science", "English", "History")

        );

    }

 

    @Override

    public Subject clone() throws CloneNotSupportedException {

        Subject obj = (Subject)super.clone();

        obj.subjects = new HashSet<>(this.subjects);

 

        return obj;

    }

 

    @Override

    public String toString() {

        return subjects.toString();

    }

 

    public Set getSubjects() {

        return subjects;

    }

}

 

// Обратите внимание, что `Student` реализует интерфейс `Cloneable`

class Student implements Cloneable

{

    private String name;        // неизменяемое поле

    private int age;            // примитивное поле

 

    private Subject subjects;

    private Map map;

 

    public Student(String name, int age)

    {

        this.name = name;

        this.age = age;

 

        map = new HashMap() {{

            put(name, age);

        }};

 

        subjects = new Subject();

    }

 

    @Override

    public String toString()

    {

        return Arrays.asList(name, String.valueOf(age),

                subjects.toString()).toString();

    }

 

    @Override

    public Object clone() throws CloneNotSupportedException {

        Student student = (Student) super.clone();

 

        // примитивные поля типа int не копируются, так как их содержимое

        // уже скопировано

 

        // Строка неизменна

 

        // вызов `clone()` для объекта `Subject`

        student.subjects = this.subjects.clone();

 

        // создаем новый экземпляр `Hashmap`

        student.map = new HashMap<>(this.map);

 

        return student;

    }

 

    public Set getSubjects() { return subjects.getSubjects(); }

    public Map getMap() { return map; }

 

    // включаем оставшиеся геттеры и сеттеры

}

 

// Демонстрация глубокой копии объектов с помощью метода `clone()`

class Main

{

    // Вспомогательный метод для сравнения двух объектов. Он печатает мелкую копию

    // если оба объекта имеют один и тот же объект; в противном случае он печатает глубокую копию

    public static void compare(Object ob1, Object ob2)

    {

        if (ob1 == ob2) {

            System.out.println("Shallow Copy");

        }

        else {

            System.out.println("Deep Copy");

        }

    };

 

    public static void main(String[] args)

    {

        Student student = new Student("Jon Snow", 22);

 

        Student clone = null;

        try {

            clone = (Student) student.clone();

            System.out.println("Cloned Object: " + clone + '\n');

        } catch (CloneNotSupportedException ex) {

            ex.printStackTrace();

        }

 

        compare(student.getSubjects(), clone.getSubjects());

        compare(student.getMap(), clone.getMap());

 

        // любые изменения, внесенные в карту клона, не отразятся на карте ученика

        clone.getMap().put("John Cena", 40);

        System.out.println(student.getMap());

    }

}

Скачать  Выполнить код

результат:

Cloned Object: [Jon Snow, 22, [Maths, English, Science, History]]
 
Deep Copy
Deep Copy
{Jon Snow=22}

 
Обычай clone() метод утомителен в реализации, подвержен ошибкам и сложен в обслуживании. Код необходимо модифицировать каждый раз, когда в поля класса вносятся какие-либо изменения.
1   ...   25   26   27   28   29   30   31   32   ...   39


написать администратору сайта