java HashMap的put

今天在写reduce函数的时候用HashMap老是出问题。reduce的输入是<query,一串url>,reduce主要是要统计各个url的次数,最后输出"query    url1   count1    url2     count2......"的形式。于是我的相关部分代码如下:(最开始没有第5行)

Map<Text,IntWritable>urlCount=new HashMap<Text,IntWritable>();   //存放query对应的url的计数
IntWritable one=new IntWritable(1);
int count=0;
for(Text t:values){
    Text tmp=new Text(t.toString()); //这一行坑了我接近一天啊,简直丧心病狂
    if(!urlCount.containsKey(tmp)){
	urlCount.put(tmp, one);
    }else{
	count=urlCount.get(tmp).get();
	urlCount.put(tmp, new IntWritable(count+1));//urlCount里有的url计数加1
    }
}
StringBuffer sb =new StringBuffer();
for(Text t:urlCount.keySet()){
    sb.append(t.toString()+"\t"+urlCount.get(t).toString()+"\t");
}
//输出"query    url1    count1    url2    count2..."
context.write(key, new Text(sb.toString())); 

主要思路就是用一个HashMap存放<url,count>对,每来一个url先判断HashMap里有没有,有就计数加1,没有就put(url,1)。思路上没有问题,但是最后输出的结果不对。比如说跟查询q相关的url们是<q,u1><q,u2><q,u3>,即reduce的输入为<q,(u1,u2,u3)>(表述不够准确,能理解就行),照理说应该输出"qu11u21u31",但实际上输出的却是“q    u3    1    u3    1     u3    1”。深深滴费解了好久,各种尝试无果,最后突然联想到一年前遇到的一个有点点类似的问题,然后在代码里加入红色那行,问题得到解决。

我分析了一下,是不是HashMap在put的时候put的是对象的引用,入下图所示:


        当没有加上红色那行的时候,如图中①所示,for循环中由t依次遍历u1,u2,u3。三次put操作put的都是t这个引用,而t指向的对象一直在改变,最后HashMap中存储的三个key都指向了t最终指向的那个对象,即u3,所以最后会得到“q    u3    1    u3    1     u3    1”这样错误的结果。而当我加上第5行后,如图②所示,每次put操作都重新创建了一个对象,并且将该对象的引用put进去,这样的话HashMap里的三个key均不随t的改变而改变。从而得出正确结果。

这样解释可以解释得通,但是又有个问题,那就是就算put的是引用也不应该出现这样的问题啊?因为t变量分配在栈空间,指向分配在堆空间的对象,在for循环内部每一次put操作的时候,值传递,会在栈空间再分配一个变量,将t的内容拷给它,于是这个变量也指向堆空间的该对象。如果这样理解的话不应该出现①那样的问题。哎,又费解了。。。坐等大神解答

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值