Java НИКОГДА не пропускает ссылку, правильно?... правильно?

Возможный дубликат:
Является ли Java "сквозной ссылкой" ?

Сегодня я нашел необычный Java-метод:

private void addShortenedName(ArrayList<String> voiceSetList, String vsName)
{
     if (null == vsName)
       vsName = "";
     else
       vsName = vsName.trim();
     String shortenedVoiceSetName = vsName.substring(0, Math.min(8, vsName.length()));
     //SCR10638 - Prevent export of empty rows.
     if (shortenedVoiceSetName.length() > 0)
     {
       if (!voiceSetList.contains("#" + shortenedVoiceSetName))
         voiceSetList.add("#" + shortenedVoiceSetName);
     }
}

В соответствии со всем, что я прочитал о Java-поведении для передачи переменных, сложных объектов или нет, этот код ничего не должен делать. Так что... я что-то упустил? Есть ли какая-то тонкость, которая была потеряна для меня, или этот код принадлежит на dailywtf?

Ответ 1

Как сказал Ритмис, Java передает ссылки по значению. Это означает, что вы можете законно называть методы mutating по параметрам метода, но вы не можете переназначить их и ожидать, что значение будет распространено.

Пример:

private void goodChangeDog(Dog dog) {
    dog.setColor(Color.BLACK); // works as expected!
}
private void badChangeDog(Dog dog) {
    dog = new StBernard(); // compiles, but has no effect outside the method
}

Изменить: В этом случае это означает, что хотя voiceSetList может измениться в результате этого метода (у него может быть добавлен новый элемент), изменения в vsName не будет видно за пределами метода. Чтобы предотвратить путаницу, я часто отмечаю параметры моего метода final, которые не позволяют им переназначить (случайно или нет) внутри метода. Это позволит вообще не компилировать второй пример.

Ответ 2

Java передает ссылки по значению, поэтому вы получаете копию ссылки, но ссылочный объект тот же. Следовательно, этот метод модифицирует список ввода.

Ответ 3

Сами ссылки передаются по значению.

Из Java Как программировать, 4-е издание от Deitel и Deitel: (стр. 329)

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

Использовал эту книгу, изучая Java в колледже. Прекрасная ссылка.

Вот хорошая статья, объясняющая это. http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html

Ответ 4

Ну, он может манипулировать ArrayList - который является объектом... если вы передаете ссылку на объект вокруг (даже пройденный значением), изменения этого объекта будут отражены на вызывающем. Это вопрос?

Ответ 5

Я думаю, вы сбиты с толку, потому что vsName изменен. Но в этом контексте это всего лишь локальная переменная на том же уровне, что и shortenedVoiceSetName.

Ответ 6

Мне непонятно, какой именно вопрос в коде есть. Java имеет значение pass-by-value, но массивы являются pass-by-reference, поскольку они не передают объект, а только указатели! Массивы состоят из указателей, а не реальных объектов. Это делает их очень быстрыми, но также делает их опасными для обработки. Чтобы решить эту проблему, вам нужно клонировать их, чтобы получить копию, и даже тогда она будет только клонировать первое измерение массива.

Более подробно см. Мой ответ здесь: на Java, что такое мелкая копия? (также см. мои другие ответы)

Кстати, есть некоторые преимущества, поскольку массивы - это только указатели: вы можете (ab) использовать их как синхронизированные объекты!