Java中的String、StringBuilder、StringBuffer类

本文介绍了Java中处理字符串的三个类:String、StringBuilder和StringBuffer。String是不可变的,适合多线程但效率低,频繁拼接时会产生大量对象。StringBuilder是可变的,非线程安全,单线程环境下性能更高。StringBuffer与StringBuilder类似,但它是线程安全的,适合多线程环境,但性能略逊于StringBuilder。
摘要由CSDN通过智能技术生成

Java中的String、StringBuilder、StringBuffer类


前言

字符串类型是我们开发时使用比较多的数据类型了,下面浅谈一下Java的几个字符串类:String、StringBuilder、StringBuffer。三种方式本质上都是对基本数据类型char进行操作的。

String、StringBuilder和StringBuffer都是Java中用于处理字符串的类,它们有一些共同点和区别。

  • String:String是不可变的字符串类,一旦创建就不能被修改。每次对String进行修改操作,都会创建一个新的String对象。这种特性使得String在多线程环境下是线程安全的。但是频繁的字符串拼接操作会导致大量的临时对象创建,对性能有一定的影响。
  • StringBuilder:StringBuilder是可变的字符串类,可以进行字符串的修改操作。StringBuilder的操作是非线程安全的,适用于单线程环境下的字符串拼接操作。由于StringBuilder不会创建新的对象,所以在频繁的字符串拼接操作中,性能比String要好。
  • StringBuffer:StringBuffer也是可变的字符串类,和StringBuilder类似,可以进行字符串的修改操作。不同的是,StringBuffer的操作是线程安全的,适用于多线程环境下的字符串拼接操作。由于StringBuffer会创建新的对象,所以在频繁的字符串拼接操作中,性能比StringBuilder要差

一、String类

Java中的String类是一个不可变的字符串类,它是由字符序列组成的。一旦创建了String对象,就不能修改它的值。如果对String对象进行修改操作,实际上是创建了一个新的String对象。

  • Java 中规定所有用双引号括号起来的,皆为String对象且不可改变
  • 双引号括号起来的String对象放在堆区的字符串常量池中,当需要使用时将指针指向常量池的字符。

我们看下面的面试题来了解String对象:

  1. 请分析以下字符串对象是否改变,并且说明详细原因。
public class StringDemo {
	public static void main(String[] args) {
		String s = "string1";
		s = "string2";
		/*
		字符串对象是不会被改变的,咋一眼看上去s对象被改变了
		,但实际上"string1"和"string2"是不同的对象,s仅仅
		是被重新赋值了而已。分别打印s的地址我们就能发现,s的
		地址已经改变了。
		
		// 类似于
		Student stu = new Student("小明");
		stu = new Student("小王");
		*/
	}
}
  1. 请分析以下输出结果,并说明原因。
public class StringDemo {
	public static void main(String[] args) {
		String s1 = "string";
		String s2 = "string";
		System.out.println(s1 == s2);  
		// 输出true
		// 首先明确:== 比较的是值。
		// String类型是引用数据类型,所以s1、s2其实是一个地址值。
		// s1、s2同时指向"string"对象的地址(字符串常量池是复用的),所以结果输出true。 
	}
}
public class StringDemo {
	public static void main(String[] args) {
		String s1 = "string";
		String s2 = new String("string");
		System.out.println(s1 == s2);  
		// 输出false
		// s1指向字符串常量池的"string"对象
		// s2则是指向堆区的"string"对象,因为new String("string")操作在堆区非常量池创建对象,且总是比直接用双引号创建方式多一次创建对象的操作。
		// new String("string")首先检查字符串常量池有没有"string"对象,没有则创建,之后再将字符串常量池"string"对象的值复制再创建一个新的String对象。
	}
}
public class StringDemo {
	public static void main(String[] args) {
		String s1 = "string";
		String s2 = "str";
		String s3 = s2 + "ing";
		System.out.println(s1 == s3);  
		// 输出false
		// s1指向字符串常量池的"string"对象
		// 我们知道对象是不能直接使用操作符的,"+"号被String类重载了,当遇到 + 号时,String类会使用StringBuilder/StringBuffer进行字符串的构造。
		// 变量s2 + 字符串常量"ing"时,String类会创建新的对象于堆区的其他区域中,所以s3则是指向堆区的"string"对象。
		// 所以 s1 != s3
	}
}
public class StringDemo {
	public static void main(String[] args) {
		String s1 = "string";
		String s2 = "str" + "i" + "ng";
		System.out.println(s1 == s2);  
		// 输出true
		// s1指向字符串常量池的"string"对象
		// 对象是不能直接使用操作符的,"+"号被String类重载了,当遇到 + 号时,String类会使用StringBuilder/StringBuffer进行字符串的构造。
		// "str" + "i" + "ng" 由于都是字符串常量对象,所以直接引用字符串常量池,所以s3指向字符串常量池的"string"对象。
		// 所以 s1 == s3 ,注意与上一个demo的区别。
	}
}

在业务中,我们普遍认为字符串内容相等即字符串相等,不关心地址问题,所以在进行字符串比较的时候一般不会使用==进行比较,String类提供了equal()方法进行字符串内容的比较且推荐使用双引号方式进行初始化,效率比 new String()要高

String对象遍历:

public class StringDemo {
	public static void main(String[] args) {
		
	    // 方式一:使用charAt()方法
		String str = "Hello";
		for (int i = 0; i < str.length(); i++) {
		   char c = str.charAt(i);
		   // 对字符进行处理
		}
		
		// 方式二:将String转换为字符数组
		String str = "Hello";
		char[] charArray = str.toCharArray();
		for (char c : charArray) {
		    // 对字符进行处理
		}
		
	}
}

推荐将String转换为字符数组再遍历。 显然,使用charAt()进行遍历每一轮循坏都要调用一次length()与charAt(i)方法,而方法的调用是需要时间开销的,而方式二则是以空间换时间的方式进行遍历,显然效率是优于使用charAt()进行遍历的。

二、StringBuilder类

StringBuilder类是Java中可变的字符串类,它可以进行字符串的修改操作。与String类不同,StringBuilder对象的值可以被修改,而不会创建新的对象

StringBuilder类提供了许多用于操作字符串的方法,例如追加字符串、插入字符串、删除字符等。它还可以通过链式调用方法来进行多个操作。

面试考点:StringBuilder的扩容机制

public class StringBuilder{
    public static void main(String args[]){
    	// 设置StringBuilder初始化容量为10
        StringBuilder sb1 = new StringBuilder(10);
        System.out.println(sb1.capacity());  // 输出10
        // 可以添加超过容量的字符,StringBuilder会自动扩容
        sb1.append("StringBuilder StringBuilder StringBuilder StringBuilder");
        System.out.println(sb1.capacity());  // 输出34

    	// 不设置初始化容量
        StringBuilder sb2 = new StringBuilder();
        System.out.println(sb2.capacity());  // 输出16,不设置系统默认为16。
        sb2.append("StringBuilder StringBuilder StringBuilder StringBuilder");
        System.out.println(sb2.capacity());  // 输出34
		
		// 扩容规则:字符大于16则 将容量变为(16+1)*2 ,大于 (16+1)*2 = 34 则 将容量变为(34+1)*2 = 70...
		// 字符大于容量将 容量扩为原本的(n+1)* 2
    }
}

同时StringBuilder提供toString()方法转化为String对象。

由于StringBuilder对象的可变性,它在单线程环境下比String类更高效。在频繁的字符串拼接操作中,使用StringBuilder可以避免创建大量的临时对象,提高性能。

然而,需要注意的是,StringBuilder类是线程不安全的。如果在多线程环境下使用StringBuilder进行字符串操作,可能会导致线程安全问题。如果需要在多线程环境下进行字符串操作,应该使用线程安全的StringBuffer类。

总之,StringBuilder类是Java中可变的字符串类,适用于单线程环境下的字符串拼接操作,可以提高性能。

三、StringBuffer类

StringBuffer类是Java中可变的字符串类,它和StringBuilder类类似,可以进行字符串的修改操作。和StringBuilder不同的是,StringBuffer类的操作是线程安全的。

由于StringBuffer对象的可变性和线程安全性,它适用于多线程环境下的字符串操作。在多个线程同时访问和修改同一个StringBuffer对象时,不会出现线程安全问题。

StringBuffer类提供了许多用于操作字符串的方法,例如追加字符串、插入字符串、删除字符等。它也可以通过链式调用方法来进行多个操作。

面试考点:StringBuffer如何实现的线程安全

  • 通过查看源码,可以知道,StringBuffer的基本方法上都有synchronized关键字,即加上了同步锁,实现线程同步,解决线程安全问题。
  • 方法级同步锁极大的影响了效率,所以StringBuffer的效率是低于StringBuilder的。

此外,由于StringBuffer会创建新的对象,所以在频繁的字符串拼接操作中,性能比StringBuilder要差。如果在单线程环境下进行字符串拼接操作,推荐使用StringBuilder;如果在多线程环境下进行字符串拼接操作,推荐使用StringBuffer。

总之,StringBuffer类是Java中可变的、线程安全的字符串类,适用于多线程环境下的字符串操作。

总结

综上所述,

  • 如果在单线程环境下进行字符串拼接操作,推荐使用StringBuilder;
  • 如果在多线程环境下进行字符串拼接操作,推荐使用StringBuffer;
  • 如果不需要修改字符串,只是进行字符串的读取操作,可以使用String;
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值