2011-03-13 79 views
0

我有使用HashMap和泛型的Java代码如下一段:为什么Java的HashMap具有不同对象的不同行为?

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; 
    } 
} 

打印出以下几点:

0 
1 

我希望它打印或者两者的人(如果我修改参考)或两个零(如果我正在修改值)。那么为什么对于从整数到整数的映射,从整数到事物的行为不同?

回答

5

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

+0

你的意思是说int不可变,还是Integer? – ohq 2011-03-13 22:47:32

+0

如果我没有记错,两者(就像String一样)。 – 2011-03-13 22:51:09

+4

实际上,如果对象是不可变的,那并不重要。如果你做了'X x = map.get(0); x = somethingElse;',如果'X'是不可变的,那并不重要。你正在重新分配一个局部变量,它不会改变原来的'x'中的任何东西。 – 2011-03-13 22:57:36

1

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

+0

是的,这都是关于参考的,宝贝:是改变地图中物体属性的代码。 – 2011-03-13 22:42:24

0

我想i = i + 1;将不会在对象上更新,因为在您分配给基元时get将按值复制。原始更新因此不会反映在地图中,因为您没有参考。通过Thing中的下一个例子,您直接分配给Thing的公共基元,所以再次按值 - 但是您更新了公共int。

+0

即使在将int i = imap.get(0)更改为Integer i = imap.get(0)之后,我仍然得到0作为第一个打印语句的结果 – ohq 2011-03-13 22:45:44

+0

通过对对象执行+我认为您自动复制它到一个int。虽然我可能是错的。 – Jim 2011-03-13 22:48:18

+0

不,它不是:将它改为i = new Integer(i + 1)没有任何区别。 – ohq 2011-03-13 22:50:24

0

这是因为当您从第一个映射(通过将整数分配给int)抓取它时,您将自动拆箱Integer值。此时,您不使用Integer引用,而是使用int基元,与映射中保存的Integer引用没有任何关系。因为java整数是不可变的,所以没有办法做你想在这里演示的东西。无法修改由映射中整数引用保持的内部基元int。你必须输入一个新的整数来改变键值为0的值。

0

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

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

...让你到位于给定位置的散列映射中的对象的引用,然后修改的成员变量的引用对象的。然后,println语句使用now-modified成员变量检索对同一对象的另一个引用。

相关问题