1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/wizardforcel-thinking-in-java-zh

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
12.1 传递引用.md 7.1 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 11.03.2025 09:15 d56454c

12.1 Передача ссылок

При передаче ссылки в метод указывается всё ещё тот же самый объект. Простой эксперимент может это показать (если возникают проблемы при выполнении этой программы, обратитесь к разделу 3.1.2 главы 3 «Присваивание»):

//: PassHandles.java
// Передача ссылок друг другу
package c12;

public class PassHandles {
  static void f(PassHandles h) {
    System.out.println("h внутри f(): " + h);
  }
  public static void main(String[] args) {
    PassHandles p = new PassHandles();
    System.out.println("p внутри main(): " + p);
    f(p);
  }
} ///:~

Метод toString() автоматически вызывается при выводе строки, а PassHandles наследует от Object, не переопределяя toString(). Поэтому используется версия toString() класса Object, которая выводит имя класса объекта и его фактическое местоположение в памяти (не адрес ссылки, а реальное место хранения объекта). Вывод будет таким:

p внутри main(): PassHandles@1653748
h внутри f(): PassHandles@1653748

Как видно, ссылки p и h указывают на один и тот же объект. Это эффективнее, чем создание нового объекта PassHandles, позволяя отправлять параметры в методы. Однако это также приводит к важной проблеме.

12.1.1 Проблема синонимовСинонимами называются несколько ссылок, указывающие на один и тот же объект, как показано в примере выше. Если кто-то что-то записывает в этот объект, возникает проблема синонимов. Если остальные владельцы ссылок не хотят изменений этого объекта, они могут столкнуться с нежелательными последствиями. Это можно продемонстрировать следующим простым примером:```java

//: 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); } } ///:~


Для этой строки:

```java
Alias1 y = x; // Присвоение ссылки

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

x.i++;

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

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 handle) {
    handle.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
```

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

Обычно мы вызываем метод для получения значения его возвращаемого типа или изменения состояния того объекта, который был передан ему. Редко требуется вызывать метод для изменения его аргументов; это называется использованием побочных эффектов (Side Effects). Поэтому если создаётся метод, который изменяет свои аргументы, следует явно указать это пользователю и предупредить о возможных последствиях использования этого метода. Из-за этих путаниц и недостатков следует избегать изменения аргументов.

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

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/wizardforcel-thinking-in-java-zh.git
git@api.gitlife.ru:oschina-mirror/wizardforcel-thinking-in-java-zh.git
oschina-mirror
wizardforcel-thinking-in-java-zh
wizardforcel-thinking-in-java-zh
master