【问题标题】:Why does reference update automatically?为什么引用会自动更新?
【发布时间】:2013-07-04 18:53:53
【问题描述】:

我有这个代码。它应该按整数值对地图进行排序。

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 实例的参数,我给构造函数一个空的哈希图。而这张空地图保存在base中。然后我用比较器创建树形图。然后我把这些东西放在地图中,它会自动更新 ValueComparator 中称为 base 的引用。为什么传递给 ValueComparator 的地图会自动更新?实际上 base 变量应该仍然是一个空映射。不是吗?

【问题讨论】:

    标签: java map hashmap comparator treemap


    【解决方案1】:

    在 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");
    }
    
    }
    

    【讨论】:

      【解决方案2】:

      实际上,基本变量应该仍然是一个空映射。不是吗?

      不,你打电话给ValueComparator bvc = new ValueComparator(map);的那一刻

      因为this.base = base;,地图和底图都指向同一个对象

      以上证明了为什么会发生“然后我将这些东西放在地图中,它会自动更新 ValueComparator 中称为 base 的引用”。

      【讨论】:

        【解决方案3】:

        为什么传递给 ValueComparator 的映射会自动更新?

        当您将object 变量传递给方法时,您传递了reference variable 的副本。因此,调用者和被调用方法现在都将拥有相同的引用副本,因此两者都将引用堆上完全相同的object。这就是为什么一个变量对对象所做的更改会被另一个变量看到。
        这就是为什么map 传递给ValueComparator 的原因会在您将内容放入map 时自动更新。

        【讨论】:

          【解决方案4】:

          在 Java 中,对类的引用是按值传递的。因此,当您将空的HashMap 传递给ValueComparator 时,实际上是在bvc 中存储了对它的引用。然后,当您修改 HashMap 时,bvc.base 作为对它的引用,会“自动更新”。

          编辑:考虑到 Jon Skeet 的回复。

          【讨论】:

          • 不,Java 是按值传递的——但是 reference 是按值传递的。对于那些理解真正的引用传递的人来说,将其称为传递引用是令人困惑的。
          • 总是这样吗?那么我可以将字符串传递给构造函数,然后更改字符串,然后在构造的类中调用输出字符串的某个方法。会是新字符串吗?
          • @MinecraftShamrock 字符串是不可变的。但是,如果您在方法中重新分配字符串,从调用者返回并 sys.out,您将获得与调用该方法之前相同的值。这使得 java 是按值传递的事实非常清楚。
          • @MinecraftShamrock 原则上是的。但是,Java 中的 String 没有可以更改字符串的方法 - 它是不可变的
          • 如此总结当我将一个对象保存在一个变量中,然后将该变量传递给一个构造函数或方法时——然后我改变了原始变量的值,传递的对象也会改变?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-04
          • 2014-10-01
          • 2018-06-10
          • 1970-01-01
          • 2015-08-16
          相关资源
          最近更新 更多