前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你真的了解Java中的String吗(也太菜了)?

你真的了解Java中的String吗(也太菜了)?

作者头像
袁新栋-jeff.yuan
发布2020-08-26 09:45:24
3400
发布2020-08-26 09:45:24
举报

背景

我们在开发的时候,在处理字段的时候遇到大量的字符拼接的时候会使用StringBuffer和StringBuild。这是为什么呢?那就是因为String会在每一次创建的时候都会新建一个对象,原来的对象也不会被删除,还有就是说还有StringBuffer和StringBuild有什么区别呢?带着这个疑问我们看一下源码

源码阅读

  1. 我们先看一下String类
代码语言:javascript
复制
//从类上看,他使用了final关键字,说明这个类是不可以改变的,且继承了Serializable,他是可以被序列化的
public final  class String implements java.io.Serializable, Comparable<String>, CharSequence {
    //还有这个存储我们的字符串的value 也是被final 修饰了所以他这个值是不可以改变的
    private final char value[];
  1. 从上面的源码看出了String里面的存储数据的主类型是不可以变的,那我们在拼接字符串的时候是怎么实现的呢?那这里我们就得看一下String的+“”的实现原理
代码语言:javascript
复制
javac Test         编译文件
javap -c Test   查看虚拟机指令

实验一:纯字符串

public class Test {
    public static void main(String args[]) {
        String str = "a";
    }
}

// 将字符串 a 存入常数池
   0:   ldc     #2; //String a
   // 将引用存放到 1 号局部变量中
   2:   astore_1
   3:   return
实验二:纯字符串相加

public class Test {
    public static void main(String args[]) {
        String str = "a" + "b";
    }
}


   // 将字符串 ab 压入常数池
   0:   ldc     #2; //String ab
   2:   astore_1
   3:   return

实验二能够非常明显地看出,编译器在编译时产生的字节码已经将 "a" + "b" 优化成了 "ab",
同理多个字符串的相加也会被优化处理,须要注意的是字符串常量相加。

实验三:字符串与自己主动提升常量相加
public class Test {
    public static void main(String args[]) {
        String str = "a" + (1 + 2);
    }
}
// 将字符串 a3 压入常数池
   0:   ldc     #2; //String a3
   2:   astore_1
   3:   return

通过虚拟机指令能够看出,1 + 2 自己主动提升后的常量与字符串常量,虚拟机也会对其进行优化。
  1. 从上面的分析我们看出的是在+的时候没有引用变量的时候所以会在编译阶段后将java中的String直接拼接好直接存入数据库中去(因为引用变量会在运行时期才会给值)。所以说在运行时是怎样的呢? 这个时候我们再看一下StringBuilder在编译后是怎样的。
代码语言:javascript
复制
String b = new StringBuilder().append("a").append(bb).toString();
  1. 是不是很惊喜,好的那我们来解释一下为什么呢?正是因为String内部的char数组被修饰了final且是一个基本类型,所以说他这个值是不可以用了。所以需要使用我们的StringBuild来实现字符串在动态运行时的拼接。
  2. 那么我们也就可以解释,String为什么会比直接使用StringBuild而更多的内存了。因为每一次使用字符串+引用的时候都会进行茶创建StringBuilder对象将原有的StringBuilder对象又拼到现在这个StringBuilder对象。而我们直接使用StringBuilder进行apend的话是在原有的基础上进行添加的。所以说是这个原因。
  3. 那说到这里了,那它为什么不使用StringBuffer而使用StringBuilder呢?再去看看StringBuffer和StringBuilder的区别是什么?
代码语言:javascript
复制
// 看到这个类也是不能被继承的且继承了AbstractStringBuilder的抽象类
 public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
 ………………
 }
    在这里我们可以看到他是使用了锁的。
    @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
    



// 看到这个类我们也可以看到他也继承了AbstractStringBuilder
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{

    /** use serialVersionUID for interoperability */
    static final long serialVersionUID = 4383685877147921099L;

    /**
     * Constructs a string builder with no characters in it and an
     * initial capacity of 16 characters.
     */
    public StringBuilder() {
        super(16);
    }
    // 这也可以看看,他这块是没有使用Sychronized这把锁的
      @Override
    public StringBuilder append(String str) {
    // 这就是重点他也是使用了AbstractStringBuilder中的apend方法。
        super.append(str);
        return this;
    }

    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
  1. 这么对比下来他两最大的区别也就是在他的操作方法上一个有锁一个是没有锁的。那么也就是说为什么StringBuilder了呢?从性能的角度来看StringBUilder虽然不是线程3安全的,但是他的性能是优秀的。并且在String拼接引用变量的时候想想也不会出现有并发安全问题的,因为他是在编译期生成且不会被并发修改的。所以使用StringBuilder而不使用StringBuffer。

总结

  1. String 是线程安全的,因为他的变量是不可变的,也就是它是一个imutable类。
  2. String的运行时字符串拼接使用过编译器翻译成StringBuilder实现的
  3. StringBuilder和StringBuffer的区别就是一个是线程安全的一个是线程不安全的。原因也就是buffer会在操作数据的方法上加锁使其同步操作达到线程安全
  4. 其中也和HashMap和HashRTable,ArrayLIst和Vector的区别一样。

参考链接

https://www.cnblogs.com/chenlong-50954265/p/5632275.html https://blog.csdn.net/weixin_33713707/article/details/85912589

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-07-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 源码阅读
  • 总结
  • 参考链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档