【JavaSe】String类、StringBuilder、StringBuffer(超详细)

1. 前言

C语言中想要表示字符串只能使用字符数组或者字符指针,但是这种方法已经不符合面相对象的思想,而字符串应用又非常广泛,因此JAVA提供了String。(妈妈再也不用担心我不会用指针了=w=)

  • 在JAVA中只要用""括起来的字符串就是String对象
//例如
"hello";
"bite";
//都是String对象

2. 常用方法

2.1 字符串构造

1. 使用常量串构造

String是引用类型
s1是引用变量
"hello"是常量串
s1这个引用,指向了"hello"这个对象,也就是s1存的是这个对象的地址。

public static void main(String[] args){
	
	String s1 = "hello";
}

2. 直接new String对象

public static void main(String[] args){
	
	String s2 = new String("hello");
}

3. 使用字符数组进行构造

public static void main(String[] args){
	
	char[] arr = {'h','e','l','l','o'};
	String s2 = new String(arr);
}

注意:String是引用类型,内部并不存储字符串本身。
在String类的实现源码中,String类的实例变量如下:

  • String本身是一个class类,类里面有一个value数组,一个hash

在这里插入图片描述

  • 例子🌰:

在这里插入图片描述

在JDK中把用""括起来的字符串,表示为常量字符串,这些常量串存储在 方法区 字符常量池中。
为什么要有字符常量池这个概念呢?
因为在实际开发中,字符串使用的频率很高,为了提高效率,所以把字符串放入字符串常量池中。

public static void main(String[] args) {
// s1和s2引用的是不同对象 s1和s3引用的是同一对象
String s1 = new String("hello"); 
String s2 = new String("world"); 
String s3 = s1;
String s4 = "hello";
}

当字符串常量池中没有"hello"这个对象,那么就会往常量池中存入一个"hello"对象,如果下次有引用再指向"hello",程序会自动在常量池中找,是否有这个"hello",如果有就直接指向这个对象,没有则往常量池中存入一个"hello"。
所以上述代码:
执行s1这行代码时,会往常量池中存入一个"hello";
s2这行代码会存入一个"world"。
因此 s1 == s3 == s4

在这里插入图片描述

2.2 String 对象的比较

1. == 比较是否引用同一个对象

注意:对于内置类型==比较的是变量中的;对于引用类型 == 比较的是引用中的地址

2. 比较是否相同

boolean equals(Object anObject)方法:按照字典序比较(一个一个往后比较)
Object 是一个大父类,任何类都默认继承Object类。

String类重写了父类Object中equals方法,Object中equals默认按照==比较,String重写equals方法后,按照如下规则进行比较
比如:s1.equals(s2)

public static void main(String[] args) {
String s1 = new String("hello"); 
String s2 = new String("hello"); 
String s3 = new String("world");
// 虽然s1与s2引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出true 
// s1与s3引用的不是同一个对象,而且两个对象中内容也不同,因此输出false 
System.out.println(s1.equals(s2));// true
System.out.println(s1.equals(s3)); // false 
}

String重写equals方法,返回值是boolean(不需要自己重写,别人已经重写好了)

public boolean equals(Object anObject) {

// 1. 先检测this 和 anObject 是否为同一个对象比较,如果是返回true
        if (this == anObject) {
            return true;
        }
        
// 2. 检测anObject是否为String类型的对象,如果是继续比较,否则返回false
        if (anObject instanceof String) {
        
        // 将anObject向下转型为String类型对象
        
            String anotherString =(String)anObject;
            int n = value.length;
            
            // 3. this和anObject两个字符串的长度是否相同,是继续比较,否则返回false
            if (n ==anotherString.value.length{
                char v1[] = value;
                char v2[] =anotherString.value;
                int i = 0;
                
// 4. 按照字典序,从前往后逐个字符进行比较
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

3. 比较大小

  • int conpareTo(String s)方法:按照字典序进行比较。

与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。

具体比较方式:

  1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值。
  2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值。
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("ac");
        String s3 = new String("abc");
        String s4 = new String("abcdef");
        System.out.println(s1.compareTo(s2));// 不同输出字符差值-1
         System.out.println(s1.compareTo(s3));// 相同输出 0
         System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3 
        }

4. 忽略大小写,比较大小

  • int compareToIgnoreCase(String str)方法:与compareTo方式相同,但是忽略大小写比较
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("ac");
        String s3 = new String("ABC");
        String s4 = new String("ABcdef");
        System.out.println(s1.compareTo(s2));// 不同输出字符差值-1
         System.out.println(s1.compareTo(s3));// 相同输出 0
         System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3
        }

2.3 字符串查找

  • 常用查找的方法:
方法功能
char charAt(int index)返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常
int indexOf (int ch)返回ch第一次出现的位置,没有返回-1
int indexOf(int ch, int fromIndex)从fromIndex位置开始找ch第一次出现的位置,没有返回-1
int indexOf(String str)返回str第一次出现的位置,没有返回-1
int indexOf(String str, int fromIndex)从fromIndex位置开始找str第一次出现的位置,没有返回-1
int lastIndexOf(int ch)从后往前找,返回ch第一次出现的位置,没有返回-1
int lastIndexOf(int ch, int fromIndex)从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1
int lastIndexOf(String str)从后往前找,返回str第一次出现的位置,没有返回-1
int lastIndexOf(String str, int fromIndex)从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返回-1
  • 例子🌰:
public static void main(String[] args) {
 String s = "aaabbbcccaaabbbccc"; 
 System.out.println(s.charAt(3)); // 'b' 
 System.out.println(s.indexOf('c')); // 6 
 System.out.println(s.indexOf('c', 10)); // 15 
 System.out.println(s.indexOf("bbb")); // 3 
 System.out.println(s.indexOf("bbb", 10)); // 12 
 System.out.println(s.lastIndexOf('c')); // 17 
 System.out.println(s.lastIndexOf('c', 10));//8 
 System.out.println(s.lastIndexOf("bbb")); //12 
 System.out.println(s.lastIndexOf("bbb", 10));// 3
 }

2.4 字符串替换&拆分

替换方法功能
String replaceAll(String regex, String replacement)替换所有的指定内容
String replaceFirst(String regex, String replacement)替换收个内容
拆分方法功能
String[] split(String regex)将字符串全部拆分
String[] split(String regex, int limit)将字符串以指定的格式,拆分为limit组
  • 字符串替换🌰:

注意:由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串

String str = "hhhhh";
String s1 = str.replaceAll("h","w");
//把所有的'h'替换成'w';
 System.out.println(s1); //wwwww
 System.out.println(str.replaceAll("h","w"));//wwwww
 System.out.println(str); //hhhhh
  • 字符串拆分🌰:
String str = "hello hi www";
String[] ans = str.split(" ");//按空格拆分
  • 部分拆分🌰:
    下述代码只把字符串拆分为2部分
String str = "hello hi www";
String[] ans = str.split(" ",2);//按空格拆分

2.5 转化

1. 数字和字符串转化

public static void main(String[] args) { 
// 数字转字符串 
String s1 = String.valueOf(1234); 
String s2 = String.valueOf(12.34);
 String s3 = String.valueOf(true);
  String s4 = String.valueOf(new Student("Hanmeimei", 18));
 
  // 注意:Integer、Double等是Java中的包装类型
  int data1 = Integer.parseInt("1234");
double data2 = Double.parseDouble("12.34");

2. 大小写转换

注意:由于字符串是不可变对象, 转换不修改当前字符串, 而是产生一个新的字符串

public static void main(String[] args) {
 String s1 = "hello"; 
 String s2 = "HELLO"; 
 
 // 小写转大写 
 String s3 = s1.toUpperCase();
 System.out.println(s1.toUpperCase()); 
 // 大写转小写 
 System.out.println(s2.toLowerCase()); }

3. 字符串转数组

String str = "hello";
//1. 直接全部转
char[] arr = str.toCharArray();.
//2.一个一个转
	char[] ch = new char[20];
for (int i = 0;i<str.length();i++){
	ch[i] = str.charAt(i);
}

4. 格式化

与C语言的printf格式输出一样

在这里插入图片描述

2.6 字符串截取

方法功能
String substring(int beginIndex)从指定索引截取到结尾
String substring(int beginIndex, int endIndex)截取部分内容
  • 截取🌰:
String str = "helloworld" ; 
System.out.println(str.substring(5)); 
System.out.println(str.substring(0, 5));//从下标0处截取到下标4处

注意事项:

  1. 索引从0开始。
  2. 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标。

2.7 其他方法

方法功能
String trim()去掉字符串中的左右空格,保留中间空格
String toUpperCase()字符串转大写
字符串转大写字符串转小写

2.8 字符串不可变

以下来自JDK1.8中String类的部分实现:

在这里插入图片描述

String类中的字符实际保存在内部维护的value字符数组中,该图还可以看出:

  1. String类被final修饰,表明该类不能被继承。
  2. value被修饰被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中的内容可以修改。
  3. final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。
  4. 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象。

3. StringBuilder和StringBuffer

Java中又提供StringBuilder和StringBuffer类。这两个类大部分功能是相同的
String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可以修改。

  • String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
  • String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
  • StringBuilder变为String: 调用toString()方法
  • String+String 会自动拼接为一个StringBuilder对象。
String s = "hello";
s += "world";//拼接自动变为StringBuilder对象,再调用toString(),返回一个新的String 赋值给s;
//这种效率极低
//所以有了StringBuilder
  • 常用方法
方法说明
StringBuff append(String str)在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、double、float、int、long、Object、String、StringBuff的变量
char charAt(int index)获取index位置的字符
int length()获取字符串的长度
int capacity()获取底层保存字符串空间总的大小
void ensureCapacity(int mininmumCapacity)扩容
void setCharAt(int index,char ch)将index位置的字符设置为ch
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最后一次出现的位置
StringBuff insert(int offset, String str)在offset位置插入:八种基类类型 & String类型 & Object类型数据
StringBuffer deleteCharAt(int index)删除index位置字符
StringBuffer delete(int start, int end)删除[start, end)区间内的字符
StringBuffer replace(int start, int end, String str)将[start, end)位置的字符替换为str
String substring(int start)从start开始一直到末尾的字符以String的方式返回
String substring(int start,int end)将[start, end)范围内的字符以String的方式返回
StringBuffer reverse()反转字符串
String toString()将所有字符按照String的方式返回

4. 面试题

  1. String、StringBuffer、StringBuilder的区别?
  • String的内容不可修改,StringBuffer与StringBuilder的内容可以修改。
  • StringBuffer与StringBuilder大部分功能是相似的。
  • StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作。
  1. 以下总共创建了多少个String对象【前提不考虑常量池之前是否存在】
String str1 = new String("ab"); // 会创建多少个对象 
String str2 = new String("a") + new String("b"); // 会创建多少个对象

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

记得三连喔~ 👍👍🏻👍🏿

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 28
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bushi橙子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值