转载请注明出处: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);
}
结果:
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),所以基本类的包装类可以放心的去重,不用担心因对象地址不同而没有去重的问题。