Путаница в отношении передачи по значению и неизменности Java - PullRequest
5 голосов
/ 02 декабря 2011

Во время подготовки к экзамену SCJP (или OCPJP, как его теперь называют) меня интересуют некоторые насмешливые вопросы, касающиеся проходной (справочной) стоимости и неизменности.

Насколько я понимаю, когда вы передаете переменную в метод, вы передаете копию битов, которые представляют, как получить эту переменную, а не сам объект.

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

Рассмотрим мой пример здесь:

public class PassByValueExperiment
{

    public static void main(String[] args)
    {
        StringBuilder sb = new StringBuilder();
        sb.append("hello");
        doSomething(sb);
        System.out.println(sb);


        Integer i = 0;
        System.out.println("i before method call : " + i);
        doSomethingAgain(i);
        System.out.println("i after method call: " + i);
    }

    private static void doSomethingAgain(Integer localI)
    {
        // Integer is immutable, so by incrementing it, localI refers to newly created object, not the existing one
        localI++;
    }

    private static void doSomething(StringBuilder localSb)
    {
        // localSb is a different reference variable, but points to the same object on heap
        localSb.append(" world");
    }
}

Вопрос : Это только неизменные объекты, которые ведут себя таким образом, и изменяемые объекты могут быть изменены путем передачи ссылок по значению? Правильно ли мое понимание или в этом поведении есть другие льготы?

Ответы [ 2 ]

6 голосов
/ 02 декабря 2011

Нет никакой разницы между изменяемыми и неизменяемыми объектами на уровне языка - неизменность является просто свойством API класса.

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

Так что различие действительно в том, что ++ оператор делает, когда он используется в примитиве против оболочки, который не имеет ничего общего с передачей параметров.

5 голосов
/ 02 декабря 2011

Сама Java не знает, является ли объект неизменным или нет. В каждом случае вы передаете значение аргумента, которое является либо ссылкой, либо примитивным значением. Изменение значения параметра никогда не оказывает никакого влияния.

Теперь, чтобы уточнить, этот код не меняет значение параметра:

localSb.append(" world");

Это изменяет данные в объекте, к которому относится значение параметра, которое сильно отличается. Обратите внимание, что вы не назначаете новое значение localSb.

По сути, вы должны понимать, что:

  • Значение выражения (переменная, аргумент, параметр и т. Д.) Равно всегда либо ссылочное, либо примитивное значение. Это никогда объект.
  • Java всегда использует семантику передачи по значению. Значение аргумента становится начальным значением параметра.

Когда вы тщательно обдумаете эти вещи и разделите в уме понятия «переменная», «ценность» и «объект», все станет яснее.

...