Почему этот объект видоизменяется во время вызова метода?

#java

#java

Вопрос:

 public class Person {
    private String name;
    private int birthYear;

    public Person(String name) {
        this.name = name;
        this.birthYear = 1970;
    }

    public int getBirthYear() {
        return this.birthYear;
    }

    public void setBirthYear(int birthYear) {
        this.birthYear = birthYear;
    }

    public String toString() {
        return this.name   " ("   this.birthYear   ")";
    }
}

public class Example {
    public static void main(String[] args) {
        Person first = new Person("First");

        System.out.println(first);
        youthen(first);
        System.out.println(first);

        Person second = first;
        youthen(second);

        System.out.println(first);
    }

    public static void youthen(Person person) {
        person.setBirthYear(person.getBirthYear()   1);
    }
}
 

В моем руководстве говорится, что результат будет:

 First (1970)
First (1971)
First (1972)
 

Я могу следить за кодом до тех пор, пока не будет создан объект второго лица. Тогда я не понимаю, почему вызов метода youthen для объекта второго лица изменяет объект первого лица.

На мой взгляд, есть два объекта Person. Мы изменили год рождения Person first , затем скопировали значения переменных экземпляра Person first в Person second, а затем обработали значения переменных экземпляра Person second, используя метод youthen, в то время как Person first не изменился с момента предыдущего вызова метода. Я ожидал, что окончательный метод печати вернет

 First (1971)
 

Комментарии:

1. Потому что second имеет ту же ссылку в памяти, что и first

Ответ №1:

до тех пор, пока не будет создан объект второго лица

Нет. Этот код создает только один Person объект. Прямо здесь:

 new Person("First")
 

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

 Person second = first;
 

В качестве аналогии представьте, что у вас есть дом, и вы записываете адрес этого дома на двух листках бумаги. Один человек, используя свой листок бумаги, идет в дом и что-то в нем меняет. (Например, окрашивает его в новый цвет.) Затем второй человек использует свой листок бумаги, чтобы подойти к дому, и видит новый цвет. Потому что есть только один дом, независимо от того, сколько людей знают его адрес.

Чтобы создать второй Person , повторно вызовите конструктор:

 Person second = new Person("Second");
 

Комментарии:

1. Мне очень нравится аналогия между домом и адресом, спасибо!

2. Спасибо! Мне пришло в голову, что никогда не было нового оператора Person, поэтому второй объект не был создан. Это имеет смысл. Так что теперь я просто не понимаю, в чем смысл всего этого. Почему бы просто не вызвать youthen(сначала)? Можете ли вы привести мне реальный пример кода, в котором добавление второй ссылки на тот же объект решает проблему?

3. @gfries: Одним из примеров может быть ваш собственный youthen() метод. Если новая ссылка на тот же объект не была создана, а вместо нее был создан совершенно новый объект, этот метод ничего не сделает. Его person переменной будет новый объект. Он установит значение для этого нового объекта, а затем вернет его, не внося никаких изменений в исходный объект. Или когда вы вызываете методы для Person самого себя, на что будет this ссылаться, если не на тот же объект, что и переменная, для которой вы вызвали метод? Тихое дублирование объектов будет иметь серьезные последствия, нанося ущерб языку.