Философия Java

         

Дублирующие ссылки (aliacing)


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

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

// Две дублирующие ссылки на один и тот же объект.

public class Alias1 { int i; Alias1(int ii) { i = ii; } public static void main(String[] args) { Alias1 x = new Alias1(7); Alias1 y = x; // Дублирующая ссылка

System.out.println("x: " + x.i); System.out.println("y: " + y.i); System.out.println("Увеличиваем x"); x.i++; System.out.println("x: " + x.i); System.out.println("y: " + y.i); } } ///:~

В строке:

Alias1 y = x; // Дублирующая ссылка

создается новая ссылка Alias1, но вместо того чтобы указывать на созданный с использованием команды new новый объект, ей присваивается значение уже существующей ссылки. Следовательно, содержимое ссылки x (то есть адрес расположения объекта,на который указывает эта ссылка) присваивается ссылке y. Таким образом обе ссылки x и y связаны с одним и тем же объектом и увеличение значения x.i в выражении:

x.i++;

также повлечет за собой изменение значения y.i, что и наблюдается в результате выполнения примера:

x: 7 y: 7 Увеличиваем x x: 8 y: 8

Единственный способ избежать подобных ситуаций - отказ от использования дублирующих ссылок. Постарайтесь в своих программах не допускать одновременного существования более одной ссылки на один и тот же объект. Это сделает код ваших программ более удобочитаемым и простым в отладке. Однако, при передаче сслыки другому методу в качестве параметра (Java позволяет такие операции) эта ссылка автоматически дублируется и операции совершаемые с ней в методе могут влиять на состояние "внешнего" объекта (т.е. на объект, созданный вне данного метода). Например:

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


// Вызванный метод изменяет внешний объект

// используя передаваемую в качестве параметра ссылку.

public class Alias2 { int i; Alias2(int ii) { i = ii; } static void f(Alias2 reference) { reference.i++; } public static void main(String[] args) { Alias2 x = new Alias2(7); System.out.println("x: " + x.i); System.out.println("Вызов метода f(x)"); f(x); System.out.println("x: " + x.i); } } ///:~

Результатом будет:

x: 7 Вызов метода f(x) x: 8

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

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

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


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