Почему ссылка обновляется автоматически?

У меня есть этот код. Он должен упорядочить карту по целочисленному значению.

public class Main {

    public static void main(String[] args) {

        HashMap<String,Integer> map = new HashMap<>();
        ValueComparator bvc =  new ValueComparator(map);
        TreeMap<String,Integer> sorted_map = new TreeMap<>(bvc);

        map.put("A",5);
        map.put("B",4);
        map.put("C",4);
        map.put("D",2);

        System.out.println("unsorted map: "+map);

        sorted_map.putAll(map);

        System.out.println("results: "+sorted_map);


    }
}

class ValueComparator implements Comparator<String> {

    Map<String, Integer> base;
    public ValueComparator(Map<String, Integer> base) {
        this.base = base;
        System.out.println("Map: " + base);
    }

    public int compare(String a, String b) {
        if (base.get(a) >= base.get(b)) {
            return -1;
        } else {
            return 1;
        }
    }
}

И это работает нормально. Но сначала в качестве параметра для экземпляра ValueComparator я передаю конструктору пустую хэш-карту. И эта пустая карта сохраняется в базе. Затем я создаю древовидную карту с помощью компаратора. Затем я помещаю материал на карту, и он автоматически обновляет ссылку в ValueComparator с именем base. Почему карта, переданная в ValueComparator, обновляется автоматически? На самом деле переменная base должна быть пустой картой. Не так ли?


person MinecraftShamrock    schedule 04.07.2013    source источник


Ответы (4)


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

Нет, в тот момент, когда вы позвоните ValueComparator bvc = new ValueComparator(map);

и карта, и базовая карта относятся к одному и тому же объекту из-за this.base = base;

И выше объясняется, почему «Затем я помещаю материал на карту, и он автоматически обновляет ссылку в ValueComparator, называемом base».

person zerocool    schedule 04.07.2013

В java все переменные передаются по значению (копия ссылки), поэтому у вас будет 2 переменные, которые ссылаются на один и тот же объект... поэтому, когда вы изменяете этот объект, он отражается в другом.

Например :

public class Test{

public static void main(String args []){
   Test test = new Test();
   Collection<String> collection = new LinkedList<>();
   collection.add("a");
   collection.add("b");
   someMethod(collection);
   System.out.println(collection); // will print [a,b];
   modifyCollection(collection);
   System.out.println(collection); // will print [a,b,c];
}

public void modifyCollection(Collection collection){
    collection.add("c");
}

public void someMethod(Collection collection){
    collection = new ArrayList();
    collection.add("nasda");
}

}
person nachokk    schedule 04.07.2013

Почему карта, переданная в ValueComparator, обновляется автоматически?

Когда вы передаете переменную object в метод, вы передаете копию переменной reference variable. Следовательно, и вызывающий, и вызываемый метод теперь будут иметь идентичную копию ссылки, и, таким образом, оба будут ссылаться на одно и то же точное object в куче. Вот почему изменения, сделанные в объекте одной переменной, видны другой переменной.
Вот почему map, переданное в ValueComparator, обновляется автоматически, когда вы помещаете материал в map.

person Mac    schedule 04.07.2013

В Java ссылки на классы передаются по значению. Поэтому, когда вы передаете свой пустой HashMap в ValueComparator, вы фактически сохраняете ссылку на него в bvc. Затем, когда вы изменяете HashMap, bvc.base, будучи ссылкой на него, "обновляется автоматически".

РЕДАКТИРОВАТЬ: Учел ответ Джона Скита.

person Jashaszun    schedule 04.07.2013
comment
Нет, Java передается по значению, но ссылка передается по значению. Называть его передачей по ссылке сбивает с толку тех, кто понимает истинную передачу по ссылке. - person Jon Skeet; 04.07.2013
comment
Всегда ли это так? Итак, могу ли я передать строку конструктору, затем изменить строку, а затем вызвать какой-либо метод в сконструированном классе, который выводит строку. Будет ли это новая строка? - person MinecraftShamrock; 04.07.2013
comment
Строка @MinecraftShamrock неизменна. Но если вы переназначите строку в методе, вернетесь и sys.out получите ее от вызывающей стороны, вы получите то же значение, что и до вызова метода. Что делает тот факт, что java передается по значению, очень очевиден. - person Sotirios Delimanolis; 04.07.2013
comment
@MinecraftShamrock в принципе да. Однако в Java нет методов для строки, которые могут изменить строку - она ​​неизменяема. - person nos; 04.07.2013
comment
Таким образом, когда я сохраняю объект в переменной, а затем передаю эту переменную конструктору или методу, я изменяю значение исходной переменной, и переданный объект тоже будет изменен? - person MinecraftShamrock; 04.07.2013
comment
@MinecraftShamrock я приведу пример в своем ответе, надеюсь, это поможет понять - person nachokk; 04.07.2013
comment
Номенклатура @MinecraftShamrock здесь особенно важна. Когда вы передаете ссылочную переменную методу и внутри этого метода вызываете методы или поля доступа, вы обращаетесь к ним в одном и том же объекте, на который указывает ссылка. - person Sotirios Delimanolis; 04.07.2013