【JavaSE】深入了解Java中的String类

文章目录

  • String类的重要性
  • String类的常用方法
    • String类的构造方法
    • 字符串对象的比较
    • 字符串的查找
    • 字符串的转换
    • 字符串的替换
    • 字符串的分割
    • 字符串的截取
    • 字符串去除两边空格
  • 字符串常量池(重点)
    • 引入
    • 再谈对象的创建
    • intern方法的介绍
    • 字符串的不可变性
  • StringBuilder和StringBuffer
  • 常见面试题

String类的重要性

因为字符串应用的广泛,所以Java中提供了String类来对字符串进行操作

我们在刷题的时候,大多数题目都是关于字符串的,所以如果更进一步的了解String类,对于我们日常刷题也是达到了事半功倍的作用,除了面试笔试题的涉及,String类在面试中也是常客
所以大家跟着我一起来学习String类吧!

String类的常用方法

String类的构造方法

String类常用的构造方法有这三种(想查看更多的构造方法可以在官方文档中查):

String s = "hello"; //直接使用字符串常量
String s = new String("hello"); //通过new String传递一个字符串常量
char[] chars = {'h','e','l','l','o'};
String s = new String(chars); //通过new String传递一个字符数组

注意:String类是引用类型,内部并不存储字符串本身,而是存的是对象的地址

看一下String类的源码:发现字符串实际保存在成员变量字符数组value

【JavaSE】深入了解Java中的String类_第1张图片

字符串对象的比较

  1. 使用==比较,对于基本类型来说比较的是值是否相等,对于引用类型来说比较的是地址是否相同
        int a = 10;
        int b = 10;
        int c = 20;
        System.out.println(a==b); //true 值相等
        System.out.println(a==c); //false 值不相等

        String s1 = new String("a"); 
        String s2 = new String("a");
        String s3 = s2;
        System.out.println(s1==s2); //false 地址不同为false
        System.out.println(s2==s3); //true 地址相同为true
  1. 使用equals方法比较

equals方法是Object类中的方法,默认是按照==也就是地址比较,但是String类重写了equals方法,使得可以比较字符串的内容是否相等

        String str1 = new String("hello");
        String str2 = new String("hello");
        String str3 = new String("world");
        System.out.println(str1.equals(str2)); //true
        System.out.println(str2.equals(str3)); //false

注意: a.equals(b),此时a不能为null,否则会发生空指针异常

        String m = null;
        String n = "a";
        System.out.println(m.equals(n));

在这里插入图片描述

  1. 使用compareTo方法比较

前面两种比较都是比较是否相同,而compareTo可以比较大小,它的返回值类型为int,它比较大小的方式是按照字典次序比较,返回比较字符的次序差值(如果前面字符相同,返回长度差值)

        String s1 = "abc";
        String s2 = "abcd";
        int ret = s1.compareTo(s2); //-1,因为前面字符相同,差值为长度差
        System.out.println(ret);
        String s3 = "a";
        String s4 = "d";
        System.out.println(s4.compareTo(s3)); //3 d比a多了3

注意: a.compareTo(b),a和b都必须不能为null,否则会发生空指针异常

  1. 使用compareToIgnoreCase方法比较

该方法与上述compareTo方法比较方式相同,只是忽略了大小写进行比较

字符串的查找

字符串查找是字符串使用最频繁的操作的之一,经常刷题的小伙伴可以感受的到哦

方法 功能
char charAt(int index) 获取index位置上的字符
int indexOf(int c) 返回c第一次出现的位置,没有返回-1
int indexOf(int c,int fromIndex) 从fromIndex位置开始找,返回c第一次出现的位置,没有返回-1
int indexOf(String str) 返回字符串str第一次出现的位置,没有返回-1
int indexOf(String str,int fromIndex) 从fromIndex位置开始找返回字符串str第一次出现的位置,没有返回-1
int lastindexOf(int c) 从后往前找,返回c第一次出现的位置,没有返回-1
int lastindexOf(int c,int fromIndex) 从fromIndex位置开始从后往前找,返回c第一次出现的位置,没有返回-1
int lastindexOf(String str) 从后往前找,返回字符串str第一次出现的位置,没有返回-1
int lastindexOf(String str,int fromIndex) 从fromIndex位置开始从后往前找,返回字符串str第一次出现的位置,没有返回-1
        String s = "abcdef";
        System.out.println(s.charAt(2)); //c
        System.out.println(s.indexOf('b')); //1
        System.out.println(s.indexOf('d',1)); //3
        System.out.println(s.indexOf("cde")); //2
        System.out.println(s.lastIndexOf("bcd")); //1

字符串的转换

  1. 数值和字符串的转换
        //数值转化为字符串
        int a = 10;
        double b = 20;
        String sa = String.valueOf(a); //10
        String sb = String.valueOf(b); //20.0

        //字符串转为数值
        String s = "10";
        int is = Integer.valueOf(s); //字符串转为Integer,Integer->int为自动拆箱,所以可以用int直接接收
        int is1 = Integer.parseInt(s); //将字符串解析为整形,返回值为int
        double ds = Double.valueOf(s);
        double ds1 = Double.parseDouble(s);

注意: 字符串转数值类型的时候,字符串必须是可转的,否则会报类型转化异常

        String ss = "12b";
        int ssi = Integer.valueOf(ss);

在这里插入图片描述

  1. 大小写转换

toUpperCase():将字符串所有的字符转换为大写
toLowerCase():将字符串所有的字符转换为小写

        String str = "abcdEF";
        System.out.println(str.toLowerCase()); //abcdef
        System.out.println(str.toUpperCase()); //ABCDEF
  1. 数组与字符串之间的转换
        String s = "hello";
        char[] c = s.toCharArray(); //字符串转换为字符数组

        String ss = new String(c); //字符数组转换为字符串

        int[] a = {1,2,3};
        String sa = Arrays.toString(a); //数组转为字符串,带中括号 [1,2,3]
        System.out.println(sa);
  1. 格式化
        String str = String.format("%d-%d-%d",2023,2,25); 
        System.out.println(str); //2023-2-25

字符串的替换

替换可以替换所有指定的内容,也可以替换第一次出现的内容

        String s = "hello";
        String ret = s.replaceAll("l","a"); //替换所有,将l替换为a
        System.out.println(ret); //heaao

        String ret1 = s.replaceFirst("l","a"); //替换第一次出现的l为a
        System.out.println(ret1); //healo

提示:字符串是不可变的,所以每次对字符串进行修改后,会重新生成一个String对象

字符串的分割

比如有这样的一个字符串:“张三,李四,王五”,我们需要将该字符按逗号进行分割

        String str = "张三,李四,王五";
        String[] array = str.split(",");
        for(String i : array){
            System.out.println(i);
        }

在这里插入图片描述

注意: 有些特殊的字符作为分割符号需要加上转义符号

  1. 字符"|“,”*“,”+"都得加上转义字符,前面加上 “\”
  2. 而如果是 “” ,那么就得写成 “\\” .
  3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符
        String str1 = "a*b*c*d";
        String[] arr = str1.split("\\*"); //*得使用转义符
        String str2 = "a-b-c+d-e-f+g-h-i";
        String[] arr1 = str2.split("\\+|-"); //按照+和-分割

字符串的截取

方法 功能
String substring(int index) 从index位置开始一直截取到末尾
String substring(int start,int end) 从start位置开始截取到end位置,不包括end位置的字符
        String s = "abcdef";
        String ret1 = s.substring(2); //cdef  从位置2截取至末尾
        String ret2 = s.substring(2,4); //cd 截取区间为[2,4)
        System.out.println(ret1); //cdef
        System.out.println(ret2); //cd

字符串去除两边空格

使用trim()方法可以去除字符串两边的空格

注意: 不能去掉字符串中间的空格

        String ss = " abc def ";
        String ret3 = ss.trim();
        System.out.println(ret3); //abc def

字符串常量池(重点)

引入

观察下面一段代码,思考:为什么s1和s2引用的是同一个对象,而s3和s4不是呢?

        String s1 = "hello";
        String s2 = "hello";
        String s3 = new String("hello");
        String s4 = new String("hello");
        System.out.println(s1==s2); //true
        System.out.println(s1==s3); //false
        System.out.println(s3==s4); //false
    }

在Java中,为了使程序执行的更快并节省空间,Java为String类提供了字符串常量池

字符串常量池在JVM中是一个StringTable,实际是一个固定大小的HashTable,在Java8中字符串常量池的位置在

再谈对象的创建

  1. 直接使用字符串常量进行赋值
String s1 = "hello";
String s2 = "hello";

【JavaSE】深入了解Java中的String类_第2张图片

  • 使用String s1 ="hello’'创建对象时,先在字符串常量池中找,没找到,则创建字符串对象放在常量池中,再将字符串引用赋值给s1
  • 使用String s2 = "hello"创建对象时,先在字符串常量池中找,找到了,则直接将字符串引用赋值给s2
  1. 使用new创建String类对象
String s1 = "hello";
String s2 = "hello";
String s3 = new String("world");
String s4 = new String("world");

【JavaSE】深入了解Java中的String类_第3张图片

说明:只要是new出来的对象,都是唯一的,通过上面的例子,可以发现使用常量池的对象创建String字符串的方法效率更高,而且更节省空间

intern方法的介绍

intern方法是一个native方法(底层使用C++实现),作用是手动的将创建的String对象添加到字符串常量池中

看下面一段代码:

        char[] c = {'h','e','l','l','o'};
        String s1 = new String(c);
        //s1.intern();
        String s2 = "hello";
        System.out.println(s1==s2); //false

发现结果为false,因为通过字符数组创建String对象底层是将char数组进行拷贝,不会加入到常量池中,观察此时的内存分布:
【JavaSE】深入了解Java中的String类_第4张图片

将intren方法打开,观察结果:

        char[] c = {'h','e','l','l','o'};
        String s1 = new String(c);
        s1.intern();
        String s2 = "hello";
        System.out.println(s1==s2); //true

发现结果为true,观察此时内存分布:
【JavaSE】深入了解Java中的String类_第5张图片

字符串的不可变性

String是一个不可变的对象,也就是内容一旦定义就不可以改变,那为啥是不可变的呢?

看一下String底层的源码:

【JavaSE】深入了解Java中的String类_第6张图片

发现字符数组使用private final修饰的,使用final修饰说明指向不能改变,使用private修饰说明对外不提供访问接口,别的类中不能直接访问到字符数组,所以是不可变的

那字符串是如何进行修改的呢?

        String s = "hello ";
        s += "world";
        System.out.println(s);

说明:底层会创建一个StringBuilder对象,调用append对象进行字符串拼接,然后通过StringBuilder对象的toString方法构造一个新的String对象,将新构造的String对象的引用赋值给s

StringBuilder和StringBuffer

因为String对象的不可变性,为了方便字符串的修改,Java中提供了StringBuilder和StringBuffer类

StringBuilder的构造方法:

方法 功能
StringBuilder() 构造一个空的StringBuilder对象
StringBuilder(String s) 使用字符串s构造StringBuilder对象

StringBuilder的常用方法:

方法 功能
StringBuilder() 构造一个空的字符串构建器
int length() 返回构建器中代码单元的数量
StringBuilder append(String str) 追加一个字符串
StringBuilder append(char c) 追加一个代码单元
void setCharAt(int i,char c) 将第i个代码单元设置为c
StringBuilder insert(int offset,String str) 在offset位置插入一个字符串
StringBuilder insert(int offset,char c) 在offset位置插入一个代码单元
StringBuilder delete(int starIndex,int endIndex) 删除偏移量从starIndex到endIndex-1的代码单元
StringBuilder reverse() 反转字符串
String toString() 将所有字符按照String方式返回
String substring(int start) 从start开始一直到末尾的字符以String的方式返回
        StringBuilder s = new StringBuilder("hello");
        s.append(' ');
        s.append("world");
        System.out.println(s); //hello world
        System.out.println(s.length()); //11
        s.insert(6,"and"); 
        System.out.println(s); //hello andworld
        s.reverse(); 
        System.out.println(s); // dlrowdna olleh
        System.out.println(s.substring(5)); //dna olleh
        System.out.println(s.toString()); //dlrowdna olleh

String类与StringBuilder类的转换:

        String s = "hello";
        
        StringBuilder sb = new StringBuilder(s); //String -> StringBuilder
        String str = sb.toString(); //StringBuilder -> String

StringBuffer和StringBuilder的功能差不多,只不过是StringBuffer在多线程环境下是线程安全的,而StringBuilder是不安全的

StringBuffer的关键方法都加了synchronized关键字保证线程安全:

【JavaSE】深入了解Java中的String类_第7张图片

常见面试题

  1. String,StringBuilder,StringBuffer的区别?

String是不可变的,其内容不可修改,StringBuilder和StringBuffer是可变的,内容可以修改
StringBuffer是线程安全的,其关键方法使用synchronized关键字修饰,StringBuilder是线程不安全的

  1. 以下共创建了多少个String对象(常量池中不存在)?
        String str1 = new String("abc");
        String str2 = new String("hello") + new String("world");
  • str1:一个new出来的String对象,一个常量池中的对象,一共是2
  • str2:两个new出来的String对象,两个常量池中的对象,拼接会创一个StringBuilder对象,StringBuilder对象转换为String时又会创建一个String对象,将String对象的引用赋值给str2,所以一共是6

你可能感兴趣的:(JavaSE,java,开发语言)