为什么Java';s HashMap对不同的对象有不同的行为?

为什么Java';s HashMap对不同的对象有不同的行为?,java,reference,hashmap,Java,Reference,Hashmap,我使用HashMap和泛型编写了以下Java代码: import java.util.*; import java.io.*; public class Map{ static HashMap<Integer, Integer> imap; static HashMap<Integer, Thing> tmap; public static void main(String[] args){ imap = new HashMa

我使用HashMap和泛型编写了以下Java代码:

import java.util.*;
import java.io.*;

public class Map{
    static HashMap<Integer, Integer> imap;
    static HashMap<Integer, Thing> tmap;

    public static void main(String[] args){

        imap = new HashMap<Integer, Integer>();
        imap.put(0,0);
        Integer i = imap.get(0);
        i = i + 1;
        System.out.println(imap.get(0));

        tmap = new HashMap<Integer, Thing>();
        tmap.put(0,new Thing(0));
        Thing t = tmap.get(0);
        t.a = t.a + 1;
        System.out.println(tmap.get(0).a);
    }
}

class Thing{
    public int a;
    public Thing(int n){
        this.a = n;
    }
}

我希望它打印两个数字(如果我修改引用的话)或两个零(如果我修改值的话)。那么,为什么从整数到整数的映射行为与从整数到事物的映射行为不同呢?

Java的整数类型是不可变的,因此第一个示例从映射中获取值,然后用新值替换局部变量。但是,第二个示例从映射中获取对Thing实例的引用。

Java的整数类型是不可变的,因此第一个示例从映射中获取值,然后用新值替换局部变量。但是,第二个示例从映射中获取对Thing实例的引用。

通过执行i=i+1,您不会增加存储在映射中的java.lang.Integer中的值

通过执行i=i+1,您不是在增加存储在映射中的java.lang.Integer中的值

我认为I=I+1;不会在对象上更新,因为在指定给基元时,get将是值的副本。因此,原语更新不会反映在地图中,因为您不持有引用。在Thing中的下一个示例中,您将直接分配回Thing的public原语,因此再次使用值-但您将更新public int。

我认为I=I+1;不会在对象上更新,因为在指定给基元时,get将是值的副本。因此,原语更新不会反映在地图中,因为您不持有引用。在Thing中的下一个示例中,您将直接分配回该对象的公共原语,因此再次使用值-但您将更新公共int。

这是因为当您从第一个映射获取整数值时(通过将整数值分配给int),您将自动取消绑定整数值。此时,您没有使用整数引用,而是使用int原语,与映射中的整数引用没有关系


由于java整数是不可变的,所以实际上无法实现您在这里演示的内容。无法修改映射中整数引用持有的内部基元int。必须。请输入一个新整数以更改保留在键0处的值

这是因为当您从第一个映射中获取整数值时(通过将整数指定给int),您正在自动取消绑定整数值。此时,您没有使用整数引用,而是使用int原语,与映射中的整数引用没有关系


由于java整数是不可变的,所以实际上无法实现您在这里演示的内容。无法修改映射中整数引用持有的内部基元int。必须。请输入一个新整数以更改保留在键0处的值

回答问题的第二部分(“但是为什么它在第二个打印语句中打印1?”),这是因为行

Thing t = tmap.get(0);
t.a = t.a + 1;

。。。获取对位于hashmap中给定位置的对象的引用,然后修改引用对象的成员变量。然后,println语句用现在修改过的成员变量检索对同一对象的另一个引用。

回答问题的第二部分(“但是为什么它在第二个print语句上打印1?”),这是因为行

Thing t = tmap.get(0);
t.a = t.a + 1;

。。。获取对位于hashmap中给定位置的对象的引用,然后修改引用对象的成员变量。然后,println语句用现在修改过的成员变量检索对同一对象的另一个引用。

Yep,这都是关于引用的,宝贝:代码是否在更改映射中保存的对象的属性。Yep,这都是关于引用的,baby:代码是否在更改映射中保存的对象的属性。即使将int i=imap.get(0)更改为Integer i=imap.get(0),作为第一个print语句的结果,我仍然得到0。通过对对象执行+操作,我认为您可以将其自动装箱回int。不过,我可能在这方面有错误。不,这不是:将其更改为i=new Integer(i+1)没有任何区别。我想上面的Mark Peters已经找到了问题的症结所在。即使将int i=imap.get(0)更改为Integer i=imap.get(0),作为第一个print语句的结果,我仍然得到了0。通过对对象执行+操作,我想您可以将其自动装箱回int。不过,我可能在这方面是错的。不,这不是问题:将其更改为i=new Integer(i+1)没有任何区别。想想上面的Mark Peters已经找到了问题的根源。你是说int immutable还是Integer?实际上,对象是否不可变并不重要。如果你做了
xx=map.get(0);x=某物
,如果
X
是不可变的,则无所谓。您正在重新分配一个局部变量,它不会改变
x
的原始引用中的任何内容。但是,为什么它会在第二个print语句中打印1呢?在这一部分中,t是一个局部变量,我正在更改t的属性。如果没有关系,那么两个print语句应该有相同的输出。你是说int immutable还是Integer?实际上,对象是否不可变并不重要。如果你做了
xx=map.get(0);x=某物
,如果
X
是不可变的,则无所谓。您正在重新分配一个局部变量,它不会改变
x
的原始引用中的任何内容。但是,为什么它会在第二个print语句中打印1呢?在这一部分中,t是一个局部变量,我正在更改t的属性。如果没有关系,那么两个print语句应该具有相同的输出。