StringBuilder 一些思考

前提

日常对比两个数组是否一样,通常是先比较两个数组的长度,如果长度一致,则比较里面的内容是否一样。今天突发奇想, 依稀记得 字符串 比对是根据 对应字符串池中地址 比对的,会不会快一点。

过程

  • 首先,需要有数据,而且得量比较大,不然看不出什么差异
  • 需要进行对比,所以得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、Stringequals() 方法,入参是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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
请设计一个类型,提供如下方法 提示 要统计每个单词出现的次数,由于一个方法不能返回2种类型,我们需要把单词和它的出现次数封装到一个类中 去,所以,可以定义一个类型如下: 由于我们统计的有多个单词,所以,我们上面的 countSize 方法的返回类型就可以设计成 WordBean[],如下: public class PatternDemo { //此方法用来统计 content 中的英文单词个数, 请使用正则表达式来做,单词的正则表达式请自行编写, public int countWords(CharSequence content) { ... } //此方法返回一串固定的字符串,已写好,可以直接用。 public StringBuilder getContent() { //此方法的内容如下: StringBuilder builder = new StringBuilder(); builder.append("Hooray! It's snowing! It's time to make a snowman.James runs out. He makes a big pile of snow. He puts a big snowball on top. He adds a scarf and a hat. He adds an orange for the nose. He adds coal for the eyes and buttons.In the evening, James opens the door. What does he see? The snowman is moving! James invites him in. The snowman has never been inside a house. He says hello to the cat. He plays with paper towels.A moment later, the snowman takes James's hand and goes out.They go up, up, up into the air! They are flying! What a wonderful night!The next morning, James jumps out of bed. He runs to the door.He wants to thank the snowman. But he's gone."); // return builder; } //此方法统计出每个单词[不考虑大小写]出现的次数,数据结构请自行定义,设计如下: public ? countSize(CharSequence content) { //TODO ... } //注:? 处是你需要去思考,该设计什么结构来存放结
最新发布
05-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值