Java基础 | 字符串

Java基础 | 字符串

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"
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());
    }
}

上面代码的执行结果

false
false
true
false
true

String常用方法

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),减少扩容次数
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); 

常用方法

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的子串,左闭右开

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://yzt.cool/archives/2020-03-10-javastring