При передаче ссылки в метод указывается всё ещё тот же самый объект. Простой эксперимент может это показать (если возникают проблемы при выполнении этой программы, обратитесь к разделу 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
, позволяя отправлять параметры в методы. Однако это также приводит к важной проблеме.
//: 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 )