一、背景
在学习mybatis源码时,在类org.apache.ibatis.datasource.pooled.PooledConnection 中发现一些程序片段
其中:变量CLOSE定义为 private static final String CLOSE = "close";
变量methodName也为String类型
二、疑惑描述
mybatis的作者在比较字符串时,为什么要先调用hashCode()进行比较,再调用equals方法?
三、猜测
因为jdk规范要求如果两个对象的equals()为true,那么它们的hashcode()的值必相等。mybatis的作者先用字符串的hashcode()进行比较,可以提高字符串的比较效率。
但是,如果先比较hashcode值可以提高字符串比较效率,为什么String.equals()方法中,没有先比较hashcode值呢?
四、验证
用junit写了个单元测试用例进行验证,代码如下:
package com.apex.mq.rabbitmq.interotc.client;
import static org.junit.Assert.*;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class StringTest {
private static final String CLOSE = "close";
private String name;
private boolean expected;
@Parameters(name = "test compare consume time: {index}: when ({0})={1}")
public static Iterable<Object[]> data1() {
return Arrays.asList(new Object[][] { { "close", true },
{ "equals", true }, { "toString", true }, { "hashcode", true },
{ "getClass", true }, { "clone", true }, { "notify", true },
{ "notifyAll", true }, { "wait", true } });
}
public StringTest(String name, boolean expected) {
this.name = name;
this.expected = expected;
}
@Test
public void testConsumeTime() {
assertEquals(expected, testHashCode() < testEquals());
}
private long testHashCode() {
long beforeTimeMillis = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
boolean result = CLOSE.hashCode() == name.hashCode();
result = false;
}
long endTimeMillis = System.currentTimeMillis();
long consumeTime = endTimeMillis - beforeTimeMillis;
System.out.println("Method: hashCode() consume time: " + consumeTime
+ " when the string is " + name);
return consumeTime;
}
private long testEquals() {
long beforeTimeMillis = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
boolean result = CLOSE.equals(name);
result = false;
}
long endTimeMillis = System.currentTimeMillis();
long consumeTime = endTimeMillis - beforeTimeMillis;
System.out.println("Method: equals() consume time: " + consumeTime
+ " when the string is " + name);
System.out.println();
return endTimeMillis - beforeTimeMillis;
}
}
执行结果出乎意料,
hashcode()并没有equals()效率高,如下图:
五、结论(欢迎拍砖)
1、通过单元测试发现,hashcode()并没有equals()效率高,所以mybatis作者的这种写法,可能只是下意识认为这样效率高。
六、后续疑问
这种写法,会不会在大量、相似、很长的字符串比较中效率高?