Java--String字符串基础概念和常用方法

4 阅读7分钟
1.String类的理解(JDK8)
1.1类的声明
public final class String
    implements java.io.Serializable,Comparable<String>,CharSequence

> final:String类是不可被继承的
> Serializable:可序列化的接口。凡是实现此接口的类的对象就可以通过网络或本地流进行数据的传输
> Comparable:凡是实现此接口的类,其对象都可以比较大小。

1.2内部声明的属性
JDK8中:
private final char value[];  //存储字符串数据的类型
    > final:表示此value数组一旦初始化,其地址就不可变。

JDK9开始:为了节省内存空间,做了优化
private final byte[] value;  //存储字符串的数据容器

2.字符串常量的存储位置
> 字符串常量都存储在字符串常量池(StringTable)中
> 字符串常量池中不允许存放两个相同的字符串常量
> 字符串常量池,在不同的jdk版本中,存放位置不同
    JDK7以前:字符串常量池存放在方法区;
    JDK7及以后:字符串常量池存放在堆空间。

3.String的不可变 性
> 当对字符串变量进行重新赋值、拼接、替换时,需要重新指定一个字符串常量的位置进行赋值,不能再原有的位置修改

4.String实例化的两种方式
第1种方式:String s1="hello";
    > JVM先去堆内字符串常量池查找有没有“hello”对象
        > 找到了:直接让s1引用常量池已存在的对象,不创建新对象
        > 没找到:在常量池新建一个String对象,再把引用赋给s1
    > 特点:复用对象,节省内存,开发中优先使用
第2种方式:String s2=new String("hello");
    > 先处理双引号里的字面量"hello":同样去常量池查找,不存在则在常量池创建对象;
    > new String()强制在堆普通对象区开辟一块内存,生成一个全新的String实例;
        > 变量s2永远指向堆中创建的新对象,不会复用常量池引用
    > 特点:极少用。

【面试题】
String s2=new String("hello"); 在内存中创建了几个对象?
答:最多两个!
    > 一个是堆空间中new的对象,另一个是在字符串常量池中生成的字面量。
    >若常量池不存在 "hello",创建 2 个对象(常量池 1 个 + 堆 1 个);若常量池已有,只在堆创建 1 个对象。

5.String的连接操作
情况1:常量+常量:结果仍然存储在字符串常量池中,返回此字面量的地址。  (注:此时的常量可能是字面量,也可能是final修饰的常量)
情况2:常量+变量 或 变量+变量 :都会通过new的方式创建一个新的字符串,返回堆空间中此字符串对象的地址
情况3:调用字符串的intern()方法 :返回的是字符串常量池中字面量的地址。
concat():不管是常量调用此方法,还是变量调用,同样不管参数是常量还是变量,总之,调用完concat()方法后,都返回一个新new的对象。

6.String与基本数据类型、包装类之间的转换
public void test2(){
    //基本数据类型 ---> String
    int num = 10;
    //方式1
    String s1 = num + "";
    //方式2
    String s2 = String.valueOf(num);

    //String ---> 基本数据类型:调用包装类的parseXxx(String str)方法
    String s3 = "123";
    int i1 = Integer.parseInt(s3);
}

7.String与char[]之间的转换
public void test3(){
    String str = "hello";
    //String ---> char[] : 调用String的toCharArray()方法
    char[] arr = str.toCharArray();
    for (int i = 0 ; i < arr.length ; i++){
        System.out.println(arr[i]);
    }

    //char[] ---> String : 调用String的构造器
    String str1 = new String(arr);
    System.out.println(str1);
}

8.String与byte[]之间的转换
public void test4(){
    String str = new String("abc中国");
    //1. String ---> byte[] : 调用String的getBytes(String 编码名)方法
    byte[] arr = str.getBytes();  //()表示使用默认的字符集 UTF-8,UTF-8字符集中,一个汉字占用3个字节,一个字母占用1个字节。
    for (int i = 0 ; i < arr.length ; i++){
        System.out.println(arr[i]);
    }
    System.out.println();
    
    //使用gbk字符集;gbk字符集中,一个汉字占用2个字节,一个字母占用1个字节。
    //String.getBytes(String 编码名) 这个方法会抛出 UnsupportedEncodingException(不支持的编码异常),属于 Java 的受检异常(Checked Exception),必须显式处理:要么捕获,要么声明抛出。
    byte[] arr1 = str.getBytes("gbk");
    for (int j = 0 ; j < arr1.length ; j++){
        System.out.println(arr1[j]);
    }

    //UTF-8和GBK(ANSI)都向下兼容了ASCII码

    //2. byte[] --->  String
    String str1 = new String(arr);  //使用默认的字符集:utf-8
    System.out.println(str1);

    String str2 = new String(arr,"utf-8");  //显示地指明解码的字符集:utf-8
    System.out.println(str2);

    String str3=new String(arr,"gbk");
    System.out.println(str3);  //编码和解码使用的字符集不一致,导致乱码
}

9.String的构造器和常用方法
9.1 构造器
    (1) public String() : 初始化新创建的String对象,以使其表示空字符序列
    (2) public String(String original):初始化一个新创建的String对象,使其表示一个与参数相同的字符序列
    (3) public String(char[] data):使用当前参数中的字符数组来构建新的String
    (4) public String(char[] data,int offset,int count):通过字符数组的一部分来构建新的String
    (5) public String(byte[] bytes,String charsetName):通过使用指定的字符集解码当前参数中的字节数组来构建新的String

9.2 String的常用方法
    (1) boolean isEmpty():字符串是否为空(判断字符串长度是否为0null表示空指针)
    (2) int length():返回字符串长度
    (3) String concat(xx):拼接
    (4) boolean equals(Object obj):比较字符串是否相等,区分大小写
    (5) boolean equalsIgnoreCase(Object obj):比较字符串是否相等,不区分大小写
    (6) int compareTo(String other):比较字符串大小,区分大小写,按照Unicode编码值比较大小写  //String类实现了Comparable接口
    (7) int compareToIgnoreCase(String other):比较字符串大小,不区分大小写
    (8) String toLowerCase():将字符串中大写字母转为小写
    (9) String toUpperCase():将字符串中小写字母转为大写
   (10) String trim():去掉字符串前后的空白符
   (11) public String intern():结果在常量池中共享

   (12) boolean contains(xx):是否包含xx
   (13) int indexOf(xx):从前往后找当前字符串中xx,即如果有返回第一次出现的下标,如果没有则返回-1
   (14) int indexOf(String str,int fromIndex):从指定的字符串开始找,返回指定子字符串后第一次出现处的索引
   (15) int lastIndexOf(xx):从后往前找当前字符串中xx,即如果有返回最后一次出现的下标,如果没有则返回-1
   (16) int lastIndexOf(String str,int fromIndex):从指定的索引开始反向搜索,返回指定字符串在最后一次出现处的索引

   (17) String substring(int beginIndex):返回一个新字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串
   (18) String substring(int beginIndex,int endIndex):返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串)

   (19) char charAt(index):返回index位置的字符
   (20) char[] toCharArray():将此字符串转换为一个新的字符串数组返回
   (21) static String valueOf(char[] data):返回指定数组中表示该字符序列的String      //将数组转换为字符串
   (22) static String valueOf(char[] data,int offset,int count):返回指定数组中表示该字符序列的String
   (23) static String copyValueOf(char[] data):返回指定数组中表示该字符序列的String
   (24) static String copyValueOf(char[] data,int offset,int count):返回指定数组中表示该字符序列的String

   (25) boolean startsWith(xx):测试此字符串是否以指定的前缀开始
   (26) boolean startWith(String prefix,int toffset):测试此字符串从指定位置开始的字符串是否以指定字符串开始
   (27) boolean endsWith(xx):测试此字符串是否以指定的后缀结尾

   (28) String replace(char oldChar,char newChar):返回一个新的字符串,它是通过用newChar替换此字符串中出现的所有oldChar得到的,不支持正则表达式
   (29) String replace(CharSequence target,CharSequence replacement):使用指定的replacement字面值替换此字符串所有匹配target字面值的子字符串
   (30) String replacementAll(String regex,String replacement):使用给定的replacement替换此字符串所有匹配始定的正则表达式的子字符串
   (31) String replacementFirst(String regex,String replacement):使用始定的replacement替换此字符串匹配始定的正则表达式的第一个子字符串