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

转载请注明出处:

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=4longB=4,hash=4false

场景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=4longB=4,hash=4true

场景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=4longB=4,hash=4true

场景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:trueA==D:trueB==C:falseB==D:falseC==D:trueA==E:trueB==E:falseA==F:trueB==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));}}结果:

1A==l:trueB==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),所以基本类的包装类可以放心的去重,不用担心因对象地址不同而没有去重的问题。

微笑拥抱每一天,做像向日葵般温暖的女子。

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

相关文章:

你感兴趣的文章:

标签云: