String 基本介绍
String 应该是 Java 中最常用的一个对象,他不是八种基本数据类型的其中之一,但是随便翻了一下项目代码,用 String 定义的变量超过百分之八十。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
}
关于 String 的几个基本知识点在 String 类的源码定义中就能看到:
-
在 JDK8 中,String 实例的值是通过 char 数组存储的。(JDK9 时,String 实例的存储由 char 变成了
byte 数组,原因是使用 byte 数组可以减少一半的内存) -
String 类被 final 修饰,因此 String 不能被继承,value 变量被 final 修饰,因此 String
实例不能被修改 -
String 类实现了 Serializable, Comparable, CharSequence 接口。
关于字符串常量池
字符串常量池是虚拟机中的内容,但是接下来的几个问题需要用到,就简单了解下。为了让 String 字符串可以复用,Java 虚拟机中设置了一种叫做字符串常量池的东西。
Java 为了避免产生大量的 String 对象,设计了一个字符串常量池。工作原理是这样的,创建一个字符串时,JVM 首先为检查字符串常量池中是否有值相等的字符串,如果有,则不再创建,直接返回该字符串的引用地址,若没有,则创建,然后放到字符串常量池中,并返回新创建的字符串的引用地址。因此看下面这段代码:
String s1="abc";
String s2="abc";
System.out.println(s1==s2); //返回true
返回的结果就是 true,因为指向了同一个对象。
关于字符串常量池的位置,在不同版本的 JDK 中有所不同:
JDK1.7 之前字符串常量池属于运行时常量池的一部分,存放在方法区。
JDK1.7 之后字符串常量池被从方法区拿到了堆中。
String str 和 new String()有什么区别
String str 和 new String()有什么区别?区别在于,String str 创建的字符串保存在字符串常量池中,并且可复用。new String()创建的字符串按照最标准的对象创建方式,生成在堆中,并且一个 new String 会在堆中创建一个对象。
String s1="abc";
String s2=new String("abc");
System.out.println(s1==s2); //返回false
String、StringBuilder、StringBuffer 的区别
String 类中使用 final 关键字修饰字符数组来保存字符串(JDK 9 以前)
private final char value[]
JDK 9 之后使用 byte 数组保存字符串
private final byte[] value
因为使用了 final 修饰符,因此 String 是不可变的。每次改变 String 类型的值时,会生成一个新的 String 对象,然后将指针指向新的 String 对象。
StringBuilder 和 StringBuffer 都是继承 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串,但是没有用 final 关键字修饰,所以这两种对象都是可变的。
StringBuffer 对字符串的一些操作方法加上了同步锁,因此是线程安全的。
StringBuilder 没有对方法加锁,因此是线程不安全的。
StringBuilder 相比 StringBuffer 提升约 10%-15% 的速度。