HashMap.values()/HashMap.keySet()何时按引用返回以及何时按值返回



下面的代码表示通过引用返回值:

public class Playground {
    public static void main(String[] args) {
        Map<Integer, vinfo> map = new HashMap<Integer, vinfo>(); 
        map.put(1, new vinfo(true));
        map.put(2, new vinfo(true));
        map.put(3, new vinfo(true));

        for(vinfo v : map.values()){
            v.state = false;
        }
        printMap(map);
    }
    public static void printMap(Map m){
        Iterator it = m.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry pairs = (Map.Entry) it.next();
            Integer n = (Integer) pairs.getKey();
            vinfo v = (vinfo) pairs.getValue();
            System.out.println(n + "=" + v.state);
        }
    }
}
class vinfo{
    boolean state;
    public vinfo(boolean state){
        this.state = state;
    }
}

输出:
1=错误
2=错误
3=错误

在下面的代码中,它们是按值返回的。然而我正在使用Integer对象。

public class Playground {
    public static void main(String[] args) {
        Map<Integer, Integer> map = new HashMap<Integer, Integer>(); 
        map.put(1, 1);
        map.put(2, 1);
        map.put(3, 1);

        for(Integer n : map.values()){
            n+=1;
        }
        printMap(map);
    }
    public static void printMap(Map m){
        Iterator it = m.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry pairs = (Map.Entry) it.next();
            Integer n = (Integer) pairs.getKey();
            Integer n2 = (Integer) pairs.getValue();
            System.out.println(n + "=" + n2);
        }
    }
}

输出:
1=1
2=1
3=1

我怎么知道我什么时候直接更改值(或键),或者我必须执行完整的.remove()和.put().

整数是不可变的。一旦构造了Integer的特定实例,就不能更改该实例的值。但是,您可以将Integer变量设置为Integer的另一个实例(除非该变量被声明为final)。您的赋值(+=)是构造一个新的Integer对象,并设置变量n来引用它。

您的类vinfo不是一成不变的,因此其行为正如您所期望的那样。

长话短说,java对象有一些非常特殊的属性。

通常,java具有直接通过值传递的基元类型(int、bool、char、double等)。然后java有对象(所有从java.lang.Object派生的东西)。对象实际上总是通过引用来处理(引用是一个你不能触摸的指针)。这意味着,实际上,对象是按值传递的,因为引用通常不感兴趣。但是,这意味着您不能更改指向哪个对象,因为引用本身是通过值传递的。

要简化您的问题,请参阅以下代码

@Test
public void testIntegerValue() {
    Integer num = new Integer(1);
    setInteger(num);
    System.out.println(num); // still return one, why? because Integer will convert to 
                            // int internally and int is primitive in Java, so it's pass by value
}
public void setInteger(Integer i) {
    i +=1;
}

最新更新