当前位置: 首页 > news >正文

Java 基础面试题 String(一)

Java 基础面试题 String(一)

文章目录

  • Java 基础面试题 String(一)
      • String、StringBuffer、StringBuilder 的区别?
      • String 为什么是不可变的?
      • 字符串拼接用“+” 还是 StringBuilder?

文章来自Java Guide 用于学习如有侵权,立即删除

String、StringBuffer、StringBuilder 的区别?

可变性

String 是不可变的(后面会详细分析原因)。

StringBuilderStringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串,不过没有使用 finalprivate 关键字修饰,最关键的是这个 AbstractStringBuilder 类还提供了很多修改字符串的方法比如 append 方法。

abstract class AbstractStringBuilder implements Appendable, CharSequence {char[] value;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;}//...
}

线程安全性

String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilderStringBuilderStringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacityappendinsertindexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。

性能

每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

对于三者使用的总结:

  1. 操作少量的数据: 适用 String
  2. 单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
  3. 多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer

String 为什么是不可变的?

String 类中使用 final 关键字修饰字符数组来保存字符串,所以String 对象是不可变的。

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {private final char value[];//...
}

🐛 修正:我们知道被 final 关键字修饰的类不能被继承,修饰的方法不能被重写,修饰的变量是基本数据类型则值不能改变,修饰的变量是引用类型则不能再指向其他对象。因此,final 关键字修饰的数组保存字符串并不是 String 不可变的根本原因,因为这个数组保存的字符串是可变的(final 修饰引用类型变量的情况)。

String 真正不可变有下面几点原因:

  1. 保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法。
  2. String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 不可变。

相关阅读:如何理解 String 类型值的不可变? - 知乎提问

补充(来自issue 675):在 Java 9 之后,StringStringBuilderStringBuffer 的实现改用 byte 数组存储字符串。

public final class String implements java.io.Serializable,Comparable<String>, CharSequence {// @Stable 注解表示变量最多被修改一次,称为“稳定的”。@Stableprivate final byte[] value;
}abstract class AbstractStringBuilder implements Appendable, CharSequence {byte[] value;}

Java 9 为何要将 String 的底层实现由 char[] 改成了 byte[] ?

新版的 String 其实支持两个编码方案:Latin-1 和 UTF-16。如果字符串中包含的汉字没有超过 Latin-1 可表示范围内的字符,那就会使用 Latin-1 作为编码方案。Latin-1 编码方案下,byte 占一个字节(8 位),char 占用 2 个字节(16),byte 相较 char 节省一半的内存空间。

JDK 官方就说了绝大部分字符串对象只包含 Latin-1 可表示的字符。

如果字符串中包含的汉字超过 Latin-1 可表示范围内的字符,bytechar 所占用的空间是一样的。

这是官方的介绍:https://openjdk.java.net/jeps/254 。

字符串拼接用“+” 还是 StringBuilder?

Java 语言本身并不支持运算符重载,“+”和“+=”是专门为 String 类重载过的运算符,也是 Java 中仅有的两个重载过的运算符。

String str1 = "he";
String str2 = "llo";
String str3 = "world";
String str4 = str1 + str2 + str3;

上面的代码对应的字节码如下:

可以看出,字符串对象通过“+”的字符串拼接方式,实际上是通过 StringBuilder 调用 append() 方法实现的,拼接完成之后调用 toString() 得到一个 String 对象 。

不过,在循环内使用“+”进行字符串的拼接的话,存在比较明显的缺陷:编译器不会创建单个 StringBuilder 以复用,会导致创建过多的 StringBuilder 对象

String[] arr = {"he", "llo", "world"};
String s = "";
for (int i = 0; i < arr.length; i++) {s += arr[i];
}
System.out.println(s);

StringBuilder 对象是在循环内部被创建的,这意味着每循环一次就会创建一个 StringBuilder 对象。

如果直接使用 StringBuilder 对象进行字符串拼接的话,就不会存在这个问题了。

String[] arr = {"he", "llo", "world"};
StringBuilder s = new StringBuilder();
for (String value : arr) {s.append(value);
}
System.out.println(s);

如果你使用 IDEA 的话,IDEA 自带的代码检查机制也会提示你修改代码。

不过,使用 “+” 进行字符串拼接会产生大量的临时对象的问题在 JDK9 中得到了解决。在 JDK9 当中,字符串相加 “+” 改为了用动态方法 makeConcatWithConstants() 来实现,而不是大量的 StringBuilder 了。这个改进是 JDK9 的 JEP 280 提出的,这也意味着 JDK 9 之后,你可以放心使用“+” 进行字符串拼接了。关于这部分改进的详细介绍,推荐阅读这篇文章:还在无脑用 StringBuilder?来重温一下字符串拼接吧 。

大家好,我是xwhking,一名技术爱好者,目前正在全力学习 Java,前端也会一点,如果你有任何疑问请你评论,或者可以加我QQ(2837468248)说明来意!希望能够与你共同进步

http://www.lryc.cn/news/285433.html

相关文章:

  • QT中QApplication对象有且只有一个
  • HTML CSS 发光字头特效
  • 4.postman批量运行及json、cvs文件运行
  • Superset二次开发之集成链路追踪TraceID技术
  • 商品详情APP端原数据淘宝数据采集API接口代码接入示例
  • 企业官网搭建:打造专业形象的关键步骤
  • Vue2移动端项目使用$router.go(-1)不生效问题记录
  • ChatGPT与文心一言:AI助手之巅的对决
  • 前端实现贪吃蛇功能
  • 文件操作(上)
  • 用CHAT写年终总结
  • day01 深度学习介绍
  • k8s 部署 Nginx 并代理到tomcat
  • 医学图像的数据增强技术 --- 切割-拼接数据增强(CS-DA)
  • git克隆/拉取报错过早的文件结束符(EOF)的原因及解决
  • 【ARM 嵌入式 编译系列 2.5 -- GCC 编译参数学习 --specs=nano.specs选项 】
  • C语言大师(5)构造函数和析构函数
  • 安全审查常见要求
  • 最新 生成pdf文字和表格
  • 安全基础~攻防特性3
  • Windows7关闭谷歌浏览器提示“若要接收后续 Google Chrome 更新,您需使用 Windows 10 或更高版本”的方法
  • [一]ffmpeg音视频解码
  • k8s-认证授权 14
  • 在全志H616核桃派上实现USB摄像头的OpenCV颜色检测
  • mac安装部署gitbook教程
  • 有关软件测试的,任何时间都可以,软件测试主要服务项目:测试用例 报告 计划
  • 快乐过寒假,安全不放假
  • qt学习:模仿qq界面+添加资源+无边框界面+修改样式
  • 【Linux】基本指令收尾
  • 精准核酸检测 - 华为OD统一考试