java包装类的比较、hash和CollectionUtils交集原理探究

转载请注明出处:http://blog.csdn.net/gklifg/article/details/45914169

1.连等(==)比较的适用与不适用场景

场景1:

<pre name="code" class="java">public void testJava(){
	Long longA = new Long(4l);
	Long longB = (longA -2)*2;
	
	System.out.println("longA="+longA+",hash="+longA.hashCode());
<span>	</span>System.out.println("longB="+longB+",hash="+longB.hashCode());
	System.out.println(longA==longB);
}

 

结果:

longA=4,hash=4

longB=4,hash=4false

场景2:

public void testJava(){
	Long longA = new Long(4l);
	Long longB = new Long(4l);
	
	System.out.println("longA="+longA+",hash="+longA.hashCode());
<span style="white-space:pre">	</span>System.out.println("longB="+longB+",hash="+longB.hashCode());
	System.out.println(longA==longB);
}

结果:

longA=4,hash=4
longB=4,hash=4
false

场景3:

public void testJava(){
	Long longA = 4l;
<span style="white-space:pre">	</span>Long longB = 4l;
	
	System.out.println("longA="+longA+",hash="+longA.hashCode());
<span style="white-space:pre">	</span>System.out.println("longB="+longB+",hash="+longB.hashCode());
	System.out.println(longA==longB);
}
结果:

longA=4,hash=4
longB=4,hash=4
true

场景4:

public void testJava(){
<span style="white-space:pre">	</span>Long longA = Long.parseLong("4");
<span style="white-space:pre">	</span>Long longB = Long.parseLong("4");
<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>System.out.println("longA="+longA+",hash="+longA.hashCode());
<span style="white-space:pre">	</span>System.out.println("longB="+longB+",hash="+longB.hashCode());
<span style="white-space:pre">	</span>System.out.println(longA==longB);
}

结果:

longA=4,hash=4
longB=4,hash=4
true

场景5:

public void testJava(){
	Long longA = 4l;//jvm自动分配
	Long longB = new Long(4);//手动创建
	Long longC = Long.parseLong("4");//?
	Long longD = (4-2)*2l;//?
	Long longE = (longA + 4)/2;//?
	Long longF = (longB + 8)/3;//?

	System.out.println("A==C:"+(longA==longC));
	System.out.println("A==D:"+(longA==longD));
	System.out.println("B==C:"+(longB==longC));
	System.out.println("B==D:"+(longB==longD));
	System.out.println("C==D:"+(longC==longD));
	System.out.println("A==E:"+(longA==longE));
	System.out.println("B==E:"+(longB==longE));
	System.out.println("A==F:"+(longA==longF));
	System.out.println("B==F:"+(longB==longF));
}
结果:
A==C:true
A==D:true
B==C:false
B==D:false
C==D:true
A==E:true
B==E:false
A==F:true
B==F:false

结论:可以看出:只要不是手动new出来的Long型值其他途径,包括parseLong方法,产生的对象都是jvm自动分配的对象。


2.HashSet的去重机制

HashSet实际上是HashMap的封装,所以去重机制继承HashMap的做法,而HashMap的hash函数依赖于Ojbect.hashCode(),从上面的例子可以知道,同值的包装类的hashCode是相同的,所以所有同值的Long都会被去重。Set中先被放入的对象留下,其他的都丢弃。如果吧A、B两行顺序调换,那么Set中留下的就是B了。

public void testJava(){
	Long longA = 4l;//jvm自动分配
	Long longB = new Long(4);//手动创建
	Long longC = Long.parseLong("4");//?
	Long longD = (4-2)*2l;//?
	Long longE = (longA + 4)/2;//?
	Long longF = (longB + 8)/3;//?
	
	Set<Long> longSet = new HashSet<Long>();
	longSet.add(longA);//注意这两行
	longSet.add(longB);<span style="font-family: Arial, Helvetica, sans-serif;">//注意这两行</span>
	longSet.add(longC);
	longSet.add(longD);
	longSet.add(longE);
	longSet.add(longF);
	
	System.out.println(longSet.size());
	
	for(Long l:longSet){
		System.out.println("A==l:"+(longA==l));
		System.out.println("B==l:"+(longB==l));
	}

}
结果:

1
A==l:true
B==l:false

3.CollectionUtils.intersection()的去重规则:

源码如下:

 public static Collection intersection(final Collection a, final Collection b) {
        ArrayList list = new ArrayList();
        Map mapa = getCardinalityMap(a);//key为a的元素,value为元素出现次数,下同
        Map mapb = getCardinalityMap(b);
        Set elts = new HashSet(a);
        elts.addAll(b);//元素经hash去重后的并集

        Iterator it = elts.iterator();
        while(it.hasNext()) {
            Object obj = it.next();
<span style="white-space:pre">	</span>    //对于每个元素,如果a或b没有次元素,那么跳过;如果都有若干个,那么放入“个数较小一方”个该元素
<span style="white-space:pre">	</span>    //可以看到,不管做交集之前有多少个相同对象,只要他们hash一致,放入结果集的都是同一个对象
            for(int i=0,m=Math.min(getFreq(obj,mapa),getFreq(obj,mapb));i<m;i++) {
                list.add(obj);
            }
        }
        return list;
    }

源码中可以看到apache的collectionUtils.intersection()也是依赖于hashCode的(mapa、mapb都是HashMap),所以基本类的包装类可以放心的去重,不用担心因对象地址不同而没有去重的问题。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值