Думай на Java

       

Классы только для чтения


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

Одно из решений - создание неизменных объектов, относящихся к группе классов "только для чтения". Вы можете определить класс таким образом, что работа методов никак не будет отражаться на состоянии самого объекта. В таких классах использование дублирующих ссылок не приводит к возникновению каких-либо проблем, поскольку вам доступны лишь операции считывания данные из объекта, а параллельное считывание не вызывает никаких проблем. В качестве простого примера неизменных объектов может служить стандартная библиотека Java, содержащая "классы-ярлыки", созданные для примитивов всех типов. Возможно вы уже обнаружили что если вы хотите разместить int в классе- контейнере, таком как ArrayList (который содержит только ссылки на объекты), вы можете обернуть (wrap) ваш int внутри стандартной библиотеки класса Integer:

//: Приложение А:ImmutableInteger.java

// Класс Integer не может быть изменен .

import java.util.*;

public class ImmutableInteger { public static void main(String[] args) { ArrayList v = new ArrayList(); for(int i = 0; i < 10; i++) v.add(new Integer(i)); // Но как вы изменили int

// внутри Integer?

} } ///:~

Класс Integer ( как и другие "классы-обертки" примитивов) наследуют неизменность самым простым образом: просто у них нет методов, позволяющих изменять объект.

Если вам нужен объект, который содержит типы примитива, который может быть изменен, вы должны создать его самостоятельно. К счастью это очень просто:


//: Приложение А:MutableInteger.java

// Изменяемый класс-ярлык.

import java.util.*;

class IntValue { int n; IntValue(int x) { n = x; } public String toString() { return Integer.toString(n); } }

public class MutableInteger { public static void main(String[] args) { ArrayList v = new ArrayList(); for(int i = 0; i < 10; i++) v.add(new IntValue(i)); System.out.println(v); for(int i = 0; i < v.size(); i++) ((IntValue)v.get(i)).n++; System.out.println(v); } } ///:~

Примечание: n использовано для упрощения кода.

Класс IntValue может быть даже упрощен, если при инициализации по умолчанию допускается устанавливать значение в ноль (тогда вам не нужен конструктор) и если вам не надо заботиться о выводе на печать (тогда вам не нужен метод toString()):

class IntValue { int n; }

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


Содержание раздела