前提
日常对比两个数组是否一样,通常是先比较两个数组的长度,如果长度一致,则比较里面的内容是否一样。今天突发奇想, 依稀记得 字符串 比对是根据 对应字符串池中地址 比对的,会不会快一点。
过程
- 首先,需要有数据,而且得量比较大,不然看不出什么差异
- 需要进行对比,所以得2种以上方法运行,查看运行耗时之间的差异
生成数据
这里我是通过随机生成的,代码如下
List<Integer> data=new ArrayList<>(4194304);
for(int i=0;i<4194304;i++){
data.add((int)(Math.random()*(i+10)));
}
Integer a[]=data.toArray(new Integer[0]);
Integer b[]=data.toArray(new Integer[0]);
a,b 即为需要对比的两个数组。
正常流程
public static void main(String[] args) {
List<Integer> data=new ArrayList<>(4194304);
for(int i=0;i<4194304;i++){
data.add((int)(Math.random()*(i+10)));
}
Integer a[]=data.toArray(new Integer[0]);
Integer b[]=data.toArray(new Integer[0]);
int i,len;
String res;
long start=System.currentTimeMillis();
for(i=0,len=a.length;i<len;i++){
if(a[i].equals(b[i])){
continue;
}
else{
break;
}
}
res=i==len?"一样":"不一样";
long stop=System.currentTimeMillis();
System.out.println("cost time :"+ (stop-start));
System.out.println("result: "+ res);
}
这里测试 运行时间 18ms左右,感觉有点快
用结果合成字符串测试
public static void main(String[] args) {
List<Integer> data=new ArrayList<>(4194304);
for(int i=0;i<4194304;i++){
data.add((int)(Math.random()*(i+10)));
}
Integer a[]=data.toArray(new Integer[0]);
Integer b[]=data.toArray(new Integer[0]);
int i=0,len=a.length;
String res;
StringBuilder r1=new StringBuilder();
StringBuilder r2=new StringBuilder();
long start=System.currentTimeMillis();
for(i=0,len=a.length;i<len;i++){
r1.append("|"+a[i]);
r2.append("|"+b[i]);
}
res=r1.toString().equals(r2.toString())?"一样":"不一样";
// res=r1.toString()==r2.toString()?"一样":"不一样";
long stop=System.currentTimeMillis();
System.out.println("cost time :"+ (stop-start));
System.out.println("result: "+ res);
}
运行时间 2900-3000ms左右,怎么会这么慢。。
对于StringBuilder 的结果不怎么满意,想着用string测试一下
public static void main(String[] args) {
List<Integer> data=new ArrayList<>(4194304);
for(int i=0;i<4194304;i++){
data.add((int)(Math.random()*(i+10)));
}
Integer a[]=data.toArray(new Integer[0]);
Integer b[]=data.toArray(new Integer[0]);
int i=0,len=a.length;
String res;
String s1="";
String s2="";
long start=System.currentTimeMillis();
for(i=0,len=a.length;i<len;i++){
s1=s1+"|"+a[i];
s2=s2+"|"+b[i];
}
res=s1.equals(s2)?"一样":"不一样";
long stop=System.currentTimeMillis();
System.out.println("cost time :"+ (stop-start));
System.out.println("result: "+ res);
}
跑了10分钟都没结束,更加慢。。
结果分析
1、理论上来说,字符串比较的的确是 字符串池中的地址,但是,这里的字符串是通过 String a="aa"
这种方式创建的,而 StringBuilder 的 toString()
方法是 通过new
来创建的,它创建的是一个对象。。所以 如果直接用 ==
比较是 false,而且耗时基本没变。而如果 是 equals()
方法比较,则对于 ==
为 false 的情况会逐个 遍历里面的内容。
2、Stringbuilder 方法耗时明显比常规的要长的原因:StringBuilder 构建过程汇中会消耗大量时间。它的append 方法中涉及如下内容:
1)内容存储的char[]
数组扩容,这里会涉及到遍历
2)每次 append()
方法调用涉及的判断
在最后对比时,toString()
equals()
方法也会耗时。
3、两个字符串比对,明明 equals
比 ==
操作耗时(对于String
而言,equals
包含 ==
操作),但是最终缺失前者的执行时间比后者少。
理论上是没错,但是我这里是第一次比对,会初始化两个对象哈希值(hash属性 差不多有1300ms)。 但是这里又有问题,同一段代码多次运行,他们的时间不一样。
我在每次运行后使用 System.gc()
进行垃圾回收,结果变为如下
个人猜测:
1、String
的 equals()
方法,入参是Object,故this == anObject
底层是不是调用了 Object.hashCode()。而 我直接调用的 res=r1.toString()==r2.toString()?"一样":"不一样";
应该调用的是 String.hashCode()
。由此解释 == 和 equals 时间不一样
2、r1 r2生成的 new String()
是不是没释放,也没被gc回收,使得之后不用在生成对象的 hash值,故时间变短。
参考代码
链接:https://pan.baidu.com/s/15T5JPasvHwXwEAcVmSOhYA
提取码:1234