Содержимое объекта изменено в методе, но хеш-код объекта остается прежним - PullRequest
1 голос
/ 08 августа 2011

В этом фрагменте кода я передаю имя в метод, который изменяет литерал String name, но не сам объект. Когда код выходит из метода, объект (как определено хеш-кодом) остается тем же, однаконе name, который изменяется в методе.

Как мне это объяснить?

public class ObjectContentsPassByReferenceApp {
    private static void modifyObject(Bus bus) {
        bus.setName("SBS Transit");
    }

    public static void main(String args[]) {
        Bus bus;

        bus = new Bus();
        bus.setName("Trans Island Bus");

        System.out.println("Bus initially set to (hashcode): " + bus);
        System.out.println("Bus name: " + bus.getName());

        modifyObject(bus);

        System.out.println("After calling modifyObject (hashcode): " + bus);
        System.out.println("Bus name: " + bus.getName());
    }
}

class Bus {
    private String name;

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Результаты выполнения:

Bus initially set to (hashcode): sg.java.concepts.passByReference.Bus@8d2ed0
Bus name: Trans Island Bus
After calling modifyObject (hashcode): sg.java.concepts.passByReference.Bus@8d2ed0
Bus name: SBS Transit

Ответы [ 2 ]

6 голосов
/ 08 августа 2011

Вы не переопределили hashCode - поэтому он будет использовать реализацию в java.lang.Object, которая не меняется в течение жизни объекта.Вы также не переопределили equals ... что означает, что a.equals(b) вернет true только для Bus a и Bus b, если a и b относятся к одному и тому же объекту, а не к объектамс одинаковым именем.

Обратите внимание, что имена в вашем коде предполагают, что Java использует передачу по ссылке.Это не так - оно всегда использует передачу по значению, но эти значения всегда являются либо примитивами, либо ссылками, а не фактическими объектами.То же самое верно для простого присваивания и т. Д.

В вашем коде вы создаете одиночный Bus объект.Думайте об этом как о реальной жизни автобуса.На нем написано имя и тисненый серийный номер (последний является хеш-кодом).Когда вы вызываете метод, он говорит методу, как получить для объекта Bus - это не создает новый Bus.Метод приходит и переписывает имя новым, но это никак не влияет на серийный номер, который такой же, как и когда-либо.

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

1 голос
/ 08 августа 2011

Если вы хотите, чтобы хеш-код зависел от переменной (т. Е. name), вам нужно переопределить метод hashCode. Простой пример:

public class Bus {
    private String name;

    public int hashCode() {
        return name.hashCode();
    }
}

Реализация hashCode в java.lang.Object не использует никаких отражений для поиска переменных, поэтому вам почти всегда нужно переопределять hashCode.

Обратите внимание, что вы должны всегда переопределять equals, если вы переопределяете hashCode и наоборот.

Существует множество полезных инструментов, которые помогут вам реализовать hashCode. Проверьте Apache Commons lang и взгляните на их HashCodeBuilder класс.

...