转载请注明出处: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);<span style="font-family: Arial, Helvetica, sans-serif;">//元素经hash去重后的并集</span> 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> //可以看到,<span style="font-family: Arial, Helvetica, sans-serif;">不管做交集之前有多少个相同对象,只要他们hash一致,</span>放入结果集的都是同一个对象 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),所以基本类的包装类可以放心的去重,不用担心因对象地址不同而没有去重的问题。