## String
String:字符串类,所有字符串字面值都是此类的实例
### 基本特性
* String 是一个 final 类,不可被继承
* String 实现了 Serializable 接口:字符串是可序列化的
* String 实现了 Compareable 接口:字符串是可以比较大小的
### String 的不可变性
1. String 类内部定义了 final char[] value,用于存储字符串序列,对于任意 String 对象,该字符数组大小不可变
2. 字符串是常量,创建后它的值不可被更改。无论是对已有的字符串对象**重新赋值**,还是**拼接操作**,还是调用 **replace()** 方法修改,都是**重新划分了内存区域**进行重新赋值,并不是使用原有 value[] 数组进行赋值
### String 的存储位置
1. 通过字面量的方式给一个字符串赋值,此时的字符串存储在字符串**常量池**中(常量池是方法区的一部分,JDK1.8为元空间)
2. 字符串常量池中**不会存储相同内容**(通过 String 的 equals() 比较)的字符串
3. 使用 new + 构造器的方式创建字符串,字符串存储在堆中
4. 关于字符串的拼接
* 常量与常量的拼接结果存放在常量池,且常量池中不会存储相同的常量
* 只要其中有一个是变量,拼接结果就存在堆中
* 如果调用 intern() 方法,返回的字符串存在常量池中
5. String str = new String("abc"); 这条语句创建了两个对象,一个是 new 的存在堆空间中,一个是 char[] 对应的常量池中的数据 "abc"
```java
public class StringBufferTest {
public static void main(String[] args) {
String str1 = "a";
String str2 = "b";
String str3 = "ab";
String str4 = str1 + "b";
String str5 = "a" + str2;
String str6 = "a" + "b";
String str7 = new String("ab");
System.out.println(str3==str4);
System.out.println(str3==str5);
System.out.println(str3==str6);
System.out.println(str3==str7);
System.out.println(str3==str7.intern());
}
}
```
上面代码的执行结果
```shell
false
false
true
false
true
```
### String常用方法
```java
int length();
// 返回字符串长度,return value.length
char charAt(int index);
// 取指定索引位置的字符,return value[index]
boolean isEmpty();
// 判断字符串是否是空字符串,return value.length==0
String toLowerCase();
// 使用默认语言环境,将 String 中的所有字符转换为小写
String toUpperCase();
// 使用默认语言环境,将 String 中的所有字符转换为大写
String trim();
// 返回一个字符串副本,此副本去除首尾空白
boolean equals(String anotherString) ;
// 比较字符串的内容是否相同
boolean equalsIgnoreCase(String anotherString);
// 忽略大小写比较内容
String concat(String anotherString);
// 将指定字符串连接至此字符串结尾,等价于 +
int compareTo(String anotherString);
// 比较字符串大小,常用于字符串排序
String substring(int beginIndex);
// 返回一个新的字符串,它是此字符串从beginIndex开始截取到最后一个字符的子串
String substring(int beginIndex,int endIndex) ;
// 返回一个新的字符串,它是此字符串从 beginIndex 开始截取到 endIndex 的子串,左闭右开
boolean endsWith(String suffix);
// 测试此字符串是否以指定的后缀结束
boolean startsWith(String suffix);
// 测试此字符串是否以指定的前缀开始
boolean startsWith(String suffix,int toffset);
// 测试此字符串从指定索引开始的子串是否以指定的前缀开始
boolean contains(CharSequence s);
// 当且仅当此字符串包含指定的char值序列,返回true
// CharSequence 是一个接口,String、StringBuffer、StringBuilder 是三个常用实现类
int indexOf(String str);
// 返回指定字符串在此字符串中第一次出现处的索引,如果不存在指定字符串,返回-1
int indexOf(String str,int fromIndex);
// 从 fromIndex 开始查找,返回指定字符串在此字符串中第一次出现处的索引,如果不存在指定字符串,返回-1
int lastIndexOf(String str);
// 从后往前查找,返回指定字符串在此字符串中最右边(最后一次)出现处的索引
int lastIndexOf(String str,int fromIndex);
// 从指定的索引开始反向搜索,返回指定字符串在此字符串中最后一次出现处的索引
// 该字符串中存在唯一的目标子串 str 或者不存在目标子串 str 时,indexOf(str) 与 lastIndexOf(str) 返回值相同
String replace(char oldChar,char newChar);
// 返回一个新的字符串,使用 newChar 替换掉所有 oldChar
String relpace(CharSequence target,CharSequence replacement);
// 使用指定的字面值替换 replacement 替换所有字面值 target
/* 正则表达式相关的方法 */
String replaceAll(String regex,String replacement);
// 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式 regex 的子字符串
String replaceFirst(String regex,String replacement);
// 使用给定的 replacement 替换此字符串匹配给定的正则表达式 regex 的第一个子串
boolean matches(String regex);
// 此字符串是否匹配给定的正则表达式
String[] split(String regex);
// 切片拆分,根据给定正则表达式的匹配拆分此字符串
String[] split(String regex,int limit)
// 切片拆分,根据给定正则表达式的匹配拆分此字符串,regex 正则表达式分隔符,limit 分割的份数
```
### String 与其他结构的转换
* **String ---> char[]**
调用 String 的方法: char[] toCharArray();
* **char[] ---> String**
调用 String 的构造器:String str = new String(char[] value);
* **编码 String ---> byte[]**
* 调用 String 的方法: getBytes(); 使用默认的字符集进行转换
* 调用 String 的方法: getBytes(String charsetName):使用指定的字符集 charsetName 进行转换,比如 "gbk"
* **解码 byte[] ---> String**
* 调用 String 的构造器:String str = new String(byte[] bytes); 使用默认的字符集进行转换
* 调用 String 的构造器:String str = new String(byte[] bytes,String charsetname); 使用指定的字符集 charsetName 进行转换
* **注意**
* 编码过程和解码过程使用的字符集必须一致,否则出现乱码
* utf-8 中一个汉字3个字节,gbk 中一个汉字2个字节
## StringBuffer 和 StringBuilder
* 二者都是可变的字符串序列,也就是说,StringBuffer 和 StringBuilder 类的对象能够被多次的**修改**,并且**不产生新的未使用对象**。
* 二者的不同点在于
* StringBuffer **是线程安全**,StringBuilder **不是线程安全的**
* StringBuilder 相较于 StringBuffer 有速度优势,效率更高
### 说明
1. 要区分 StringBuffer 的 length() 和 capacity ,length() 获取的是 StringBuffer 底层数组当前存的字符的数量,capacity 是底层数组当前的最大容量,
2. 扩容问题:底层数组初始容量为 16,当要添加数据时,如果当前底层的数组容量不够,则将容量扩容为之前的 2倍+2(一般情况下),然后再将原来的数组复制到新数组,再执行添加
3. 尽量使用指定容量的构造器 StringBuffer(int capacity),减少扩容次数
```java
String str1 = new String("abc");
//char[] value = new char[]{'a','b','c'};
StringBuffer sb1 = new StringBuffer();
//char[] value = new char[16];
//System.out.println()
sb1.append('a');
//value[0]='a';
sb1.append('b');
//value[1]='b';
StringBuffer sb2 = new StringBuffer("abc");
//char[] value = new char["abc".length()+16];
//append(str);
```
### 常用方法
```java
StringBuffer append(String s);
// 将指定的字符串 s 追加到此字符序列
StringBuffer delete(int start, int end)
// 删除指定位置的字符,位置为左闭右开 [start,end)
StringBuffer replace(int start,int end,String str);
// 使用给定字符串 str 替换此序列的子字符串中的字符,位置为左闭右开 [start,end)
StringBuffer reverse();
// 将此字符序列用其反转形式取代
int length();
// 返回字符串长度
StringBuffer insert(int offset, String str);
// 在指定位置插入字符串 str,或其他内容
char charAt(int index);
// 取指定索引位置的字符,可用于底层字符的遍历
String substring(int beginIndex,int endIndex);
// 返回一个新的字符串,它是此字符串从beginIndex开始截取到endIndex的子串,左闭右开
```

Java基础 | 字符串