目录
不可变之字符序列String
String的特性
-
java.lang.String
类代表字符串。Java 程序中所有的字符串文字(例如"hello"
)都可以看作是此类的实例。 -
字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
-
字符串 String 类型本身是 final 声明的,意味着我们不能继承 String。
-
String 对象的字符内容是存储在一个字符数组
value[]
中的。"abc"
等效于char[] value = {‘h’,’e’,’l’,’l’,‘o’}。
|
|
- private 意味着外面无法直接获取字符数组,而且 String 没有提供 value 的 get 和 set 方法。
- final 意味着字符数组的引用不可改变,而且 String 也没有提供方法来修改 value 数组某个元素值。
- 上述两个条件保证了 String 对象一旦被创建
内容
就是不可变的。一旦对字符串进行修改,就会产生新对象。 - Java 语言提供字符串串联符号
+
,以及将其他类型对象转换为字符串的特殊支持即toString()
方法。
在 JDK9 中,value 的类型从 char[] 变成了 byte[]
|
|
String的内存结构
直接通过字面量赋值:
通过 new 创建字符串:
如图所示String str = new String(“Hello”)可能同时会创建两个String对象,一个在堆中,一个在字符串常量池中(如果程序之前从未使用过或很久没有使用过"Hello")。
字符串常量池的位置:
- Jdk1.6及之前: 有永久代,
运行时常量池
在永久代,运行时常量池包含字符串常量池。- **Jdk1.7:**有永久代,但已经逐步“去永久代”,字符串常量池从永久代里的运行时常量池分离到堆里。
- Jdk1.8及之后: 无永久代,运行时常量池在元空间,字符串常量池里依然在堆里。
如果想了解相关内容可以参考:java常量池详解 或 Java 常量池详解(一)字符串常量池
判断字符串对象是在堆中还是字符串常量池中:
- 常量 + 常量:对象在常量池中,且常量池中不会存在相同内容的常量。这里的常量既包括了字面量,也包括了用 final 修饰的常量,后文的常量中也是这个意思。
|
|
- 调用intern() 方法得到的对象:在常量池中
|
|
-
常量 + 变量 / 变量 + 常量:对象在堆中
-
concat() 方法拼接而成的字符串对象:在堆中。即使是两个常量相拼接也是在堆中,这与 concat() 的实现有关。
|
|
String 的常用 API
构造器
API | 描述 |
---|---|
public String() | 初始化新创建的 String 对象,使其表示空字符序列。 |
String(String original) | 初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。 |
public String(char[] value) | 通过当前参数中的字符数组来构造新的 String。 |
public String(char[] value,int offset, int count) | 通过字符数组的一部分来构造新的 String。 |
public String(byte[] bytes) | 通过使用平台的默认字符集解码 当前参数中的字节数组来构造新的 String。 |
public String(byte[] bytes,String charsetName) | 通过使用指定的字符集解码 当前参数中的字节数组来构造新的 String。指定的字符集只用于解码过程,Java 中所有的字符在内存中都以 Unicode 编码保存,上同。 |
|
|
String与其他结构间的转换
字符串 -> 基本数据类型、包装类:
- Integer 包装类的
public static int parseInt(String s)
:可以将由“数字”字符组成的字符串转换为整型。 - 类似地,使用 java.lang 包中的 Byte、Short、Long、Float、Double 类调相应的
parseXxx
方法可以将由“数字”字符组成的字符串,转化为相应的基本数据类型。
基本数据类型、包装类 -> 字符串:
- 调用 String 类的
public String valueOf(int n)
可将 int 型转换为字符串。 - 相应的 valueOf(byte b)、valueOf(long l)、valueOf(float f)、valueOf(double d)、valueOf(boolean b) 可由参数的相应类型到字符串的转换。
- 也可以通过将数据与空字符串拼接的方式将对应数据转为字符串类型。
字符数组 -> 字符串:
- String 类的构造器:
String(char[] value)
和String(char[] value, int offset, int length)
分别用字符数组中的全部字符和部分字符创建字符串对象。
字符串 -> 字符数组:
-
public char[] toCharArray()
:将字符串中的全部字符存放在一个字符数组中并返回该字符数组。 -
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
:提供了将指定索引范围内的字符串存放到字符数组中的方法,这个字符数组需要使用者来提供。
字符串 -> 字节数组(编码):
public byte[] getBytes()
:使用平台的默认字符集将对应 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。public byte[] getBytes(String charsetName)
:使用指定的字符集将对应 String 编码为 byte 序列,并将结果存储到新的 byte 数组。
字节数组 -> 字符串(解码):
String(byte[] bytes)
:通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。String(byte[] bytes,int offset,int length)
:用指定的字节数组的一部分,即从数组起始位置 offset 开始取 length 个字节使用默认字符集构造一个字符串对象。String(byte[] bytes, String charsetName)
或String(byte[] bytes, int offset, int length ,String charsetName)
:按照指定的编码方式进行解码。
不乱码的两个条件:
- 保证编码和解码的字符集是相同的
- 解码时对应的字节序列是完整的,没有缺少字节
|
|
常用方法
方法 | 描述 |
---|---|
boolean isEmpty() | 字符串是否为空字符串,不是判断是否为null |
int length() | 返回字符串的长度 |
String concat(String other) | 拼接两个字符串,返回一个新的字符串,原来的字符串保持不变 |
boolean equals(Object obj) | 比较字符串是否相等,区分大小写 |
boolean equalsIgnoreCase(Object obj) | 比较字符串是否相等,不区分大小写 |
int compareTo(String other) | 按照 Unicode 编码值比较字符串大小,区分大小写 |
int compareToIgnoreCase(String other) | 按照 Unicode 编码值比较字符串大小,不区分大小写 |
String toLowerCase() | 将字符串中大写字母转为小写 |
String toUpperCase() | 将字符串中小写字母转为大写 |
String trim() | 去掉字符串前后空白符 |
public String intern() | 返回与当前字符串内容相同的,位于字符串常量池中的字符串的引用 |
boolean contains(String str) | 判断字符串中是否包含 str |
int indexOf(String str) | 从前往后找当前字符串中 str,如果有则返回 str 第一次出现的下标,没有返回则返回 -1 |
int indexOf(String str, int fromIndex) | 从指定索引开始,从前往后找当前字符串中 str,如果有则返回 str 第一次出现的下标,没有返回则返回 -1 |
int lastIndexOf(String str) | 从后往前找当前字符串中 str,如果有则返回 str 第一次出现的下标,没有返回则返回 -1 |
int lastIndexOf(String str, int fromIndex) | 从指定索引开始,从后往前找当前字符串中 str,如果有则返回 str 第一次出现的下标,没有返回则返回 -1 |
String substring(int beginIndex) | 返回一个新的字符串,它是此字符串从 beginIndex 开始截取到最后的一个字符的子字符串 |
String substring(int beginIndex, int endIndex) | 返回一个新的字符串,它是此字符串从 beginIndex 开始截取到 endIndex (不包含)的子字符串。 |
char charAt(index) | 返回字符串 index 位置的字符 |
char[] toCharArray() | 将字符串转换为一个新的字符数组返回 |
static String valueOf(char[] data) | 返回一个新字符串,该字符串用整个 data 数组构建 |
static String valueOf(char[] data, int offset, int count) | 返回一个新字符串,该字符串从 data 数组的 offset 索引开始,使用 count 个字符构建字符串 |
static String copyValueOf(char[] data) | 返回一个新字符串,该字符串用整个 data 数组构建 |
static String copyValueOf(char[] data, int offset, int count) | 返回一个新字符串,该字符串从 data 数组的 offset 索引开始,使用 count 个字符构建字符串 |
boolean startsWith(String str) | 判断字符串是否以指定的前缀开始 |
boolean startsWith(String prefix, int toffset) | 判断字符串从指定索引开始的子字符串是否以指定前缀开始 |
boolean endsWith(String str) | 判断此字符串是否以指定的后缀结束 |
String replace(char oldChar, char newChar) | 返回一个新的字符串,它是通过用 newChar 替换字符串中出现的所有 oldChar 得到的,不支持正则表达式 |
String replace(CharSequence target, CharSequence replacement) | 使用指定的字面值序列替换字符串所有匹配字面值目标序列的子字符串 |
String replaceAll(String regex, String replacement) | 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串 |
String replaceFirst(String regex, String replacement) | 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串 |
可变之字符序列 StringBuffer、StringBuilder
因为 String 对象是不可变对象,虽然可以共享常量池对象,但是对于频繁的字符串的修改和拼接操作来说,String 的效率极低、空间消耗较高。因此,JDK 又在 java.lang 包提供了可变字符序列 StringBuffer
和 StringBuilder
类型。
java.lang.StringBuffer 代表可变的字符序列
,于JDK1.0中声明,可以对字符串内容进行增删查改
操作但不会产生新的对象,而是在原来的字符串中进行操作。比如:
|
|
StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且提供相关功能的方法也一样。
区分String、StringBuffer、StringBuilder
String
:不可变的字符序列;底层使用 char[] 数组存储数据(JDK8.0中)StringBuffer
:可变的字符序列;线程安全(方法有synchronized
修饰),效率较低;底层使用 char[] 数组存储数据(JDK8.0中)StringBuilder
:可变的字符序列; JDK1.5 引入,线程不安全,效率高;底层使用 char[] 数组存储数据(JDK8.0中)
|
|
|
|
就执行效率而言:
StringBuilder > StringBuffer > String
常用 API
StringBuilder、StringBuffer 的 API 是完全一致的,并且很多方法与 String 相同。
API | 描述 |
---|---|
StringBuffer append(xxx) | 提供了很多的 append() 方法,用于进行字符串追加的方式拼接 |
StringBuffer delete(int start, int end) | 删除 [start,end) 之间字符 |
StringBuffer deleteCharAt(int index) | 删除 [index] 位置字符 |
StringBuffer replace(int start, int end, String str) | 替换 [start,end) 范围的字符序列为 str |
void setCharAt(int index, char c) | 替换 [index] 位置字符为 c |
char charAt(int index) | 返回 [index] 位置上的字符 |
StringBuffer insert(int index, xx) | 在 [index] 位置插入 xx |
int length() | 返回存储的字符数据的长度 |
StringBuffer reverse() | 反转字符序列 |
int indexOf(String str) | 在当前字符序列中查询 str 的第一次出现下标 |
int indexOf(String str, int fromIndex) | 在当前字符序列 [fromIndex, 最后] 中查询 str 的第一次出现下标 |
int lastIndexOf(String str) | 在当前字符序列中查询 str 的最后一次出现下标 |
int lastIndexOf(String str, int fromIndex) | 在当前字符序列 [fromIndex, 最后] 中查询 str 的最后一次出现下标 |
String substring(int start) | 截取当前字符序列 [start,最后] |
String substring(int start, int end) | 截取当前字符序列 [start,end) |
String toString() | 返回此序列中数据的字符串表示形式 |
void setLength(int newLength) | 设置当前字符序列长度为 newLength |