Java中String,StringBuffer,StringBuilder基础知识

本文深入解析Java中的String、StringBuffer和StringBuilder的区别,包括它们的特性、使用场景及性能对比,帮助理解字符串操作的最佳实践。

原文链接

 

三者区别

  • String :不可变类,任何对String的改变都会引发新的String对象的生成,适用于少量的字符串操作的情况
  • StringBuffer :线程安全,任何对它所指代的字符串的改变都不会产生新的对象,适用多线程下在字符缓冲区进行大量操作的情况
  • StringBuilder :线程不安全,因此不适合多线程中使用,适用于单线程下在字符缓冲区进行大量操作的情况
  • 速度运行方面:StringBuilder > StringBuffer > String

String 

因为String是不可变的对象,每次对String类型改变的时候其实都等同于生成一个新的String对象,然后将指针指向新的String对象,所以经常改变内容的字符串最好不要用String,因为每次生成对象都会对系统性能产生影响,当内存多了无引用的对象,JVM的GC就会工作,频繁GC就会造成界面的卡顿,下面直接上例子:

		 String str1 = "abc";
		 char data[] = {'a','b','c'};
		 String str2 = new String(data);
		 //输出true
		 System.out.println(str1.equals(str2));
		 //输出false
		 System.out.println(str1 == str2);
		 
		 String str3 = "This is Java";
		 String str4 = new String("This is Java");
		 //输出true
		 System.out.println(str3.equals(str4));
		 //输出false
		 System.out.println(str3 == str4); 
		  
  • ==操作符的作用
  1. 比较基本数据类型是否相同
  2. 判断引用是否指向堆内存的同一块地址,也就是是否指向同一个对象
  • equasl方法的作用
  1. 判断两个变量是否对同一个对象的引用,也就是内存堆中的内容是否相同,其实就是对String对象所封装的字符串内容作比较,具体的值是否相等,如果两个String对象所封装的字符型内容相同,则equals()方法将返回true

而上面的情况因为str1str2是两个不同的对象,但是内容相等,所以==返回了false,而equals返回true,str3str4也是一样道理,从上面可以简单得出一个结论,无论上直接赋值还是通过new关键字来创建String对象,都会生成两个不同的String对象,即使字符型内容相同。

 

情况二

		 String str5 = "This is Java";
		 String str6 = "This is";
		 String str7 = "This is" + " Java";
		 //输出true
		 System.out.println(str5.equals(str7));
		 //输出true
		 System.out.println(str5 == str7); 

从上面代码可以看出,无论是用==或者equals来比较两个没有引用并且内容值是相等返回都是true,也就是String str7 = "This is" + " Java";这句话没有创建新的对象,而是引用指向str5的地址。

 

情况三

String str8 = "This is Java";

String str9 = "This is";

String str10 = str9 + " Java";

//输出true

System.out.println(str8.equals(str10));

//输出false

System.out.println(str8 == str10);

上面发现用==比较时,str8str10不是指向同一个地址,这是因为在编译时str8str9就已经确定了,而str10是引用变量,不会再编译时确定,所以会创建String对象。

 

情况四

String str11 = "This is Java";

String str12 = new String("This is Java");

String str13 = str12;


//输出true

System.out.println(str11.equals(str12));

//输出true

System.out.println(str11.equals(str13));

//输出true

System.out.println(str12.equals(str13));

//输出false

System.out.println(str11 == str13);

//输出false

System.out.println(str11 == str12);

//输出true

System.out.println(str12 == str13);

因为三个String对象的值都是相等的,所以用equals来比较是返回true,因为str13是指向str12,相当于传递引用,所以用==来比较是相等的,都是同一个对象。

一开始String str11 = "This is Java";在常量池已经创建This is Java这个常量,所以String str12 = new String("This is Java");这句代码不会再常量池创建对象,只会在堆上创建对象This is Java,也就是说new String创建字符串它其实分两步操作:

  1. 在堆上创建对象
  2. 检查常量池有没有字符串字面量,如果没有就在常量池创建常量,如果存在就不做任何操作

 

  • 情况五

		 
		 String str14 = "This is Java";
		 String str15 = "This is Java";
		 String str16 = "This is Java";
		 
		 //输出true
		 System.out.println(str14.equals(str15));
		 //输出true
		 System.out.println(str14.equals(str16));
		 //输出true
		 System.out.println(str15.equals(str16));
		 //输出true
		 System.out.println(str14 == str15); 
		 //输出true
		 System.out.println(str14 == str16); 
		 //输出true
		 System.out.println(str15 == str16); 

 

情况六

String str17 = new String("This is Java");

String str9 = str17.intern();

String str18 = "This is Java";

//输出false

System.out.println(str9 == str17);

//输出true

System.out.println(str9 == str18);

上面调用了intern这个方法,这句话就是把字符串对象加入常量池中

 

关于String总结

  1. String a = "xxx" 可能创建一个或者不创建对象,当xxx这个字符常量在String常量池不存在,会在String常量池创建一个String对象,然后a会指向这个内存地址,后面继续用这种方式继续创建xxx字符串常量,始终只有一个内存地址被分配。
  2. String a = new String("xxx")至少创建一个对象,也有可能两个。只要用到new就肯定在堆上创建一个String对象,并且检查String常量池是否存在,如果不存在就会在Stirng常量池创建这个String对象,存在就不创建。

StringBuffer字符串变量

 

api文档上,同样可以知道StringBuffer继承Object类,并实现了序列化接口,能够被添加char序列和值的对象接口,可读序列接口。和String相比,没有实现Comparable,而是实现了Appendable。它是线程安全的可变字符序列,一个类似于String的字符串缓冲区,但是不能修改,虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用的可以改变该序列的长度和内容。StringBuffer上的主要操作是appendinsert方法,可以重载这些方法,以接受任意类型的数据,每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或者插入到字符串缓冲区中。append方法始终将这些字符添加到缓冲区的末端,而insert方法则在指定的点添加字符。StringBufferString不一样,它是**字符串变量,是可以改变的对象,当对字符串做操作时,就是在对象上做操作,不会像String一样创建额外的对象进行操作。

StringBuffer str20 = new StringBuffer("This is");

//StringBuffer后面追加内容

str20.append(" Java");

System.out.println(str20); //输出:This is Java

//删除第6-8个字符

str20.delete(5, 8);

System.out.println(str20); //输出:This Java

//在9个位置插入

str20.insert(9," is good");

System.out.println(str20); //输出:This Java is good

//替换5-9

str20.replace(5, 9, "C++");

System.out.println(str20); //输出:This C++ is good

//倒序

str20.reverse();

System.out.println(str20); //输出:doog si ++C sihT


//变成大写

System.out.println(str20.toString().toUpperCase()); //输出:DOOG SI ++C SIHT


//第一种方案StringBuffer转化成String

String str21 = new String(str20);

System.out.println(str21); //输出:doog si ++C sihT


//第二种方案

String str22 = str20.toString();

System.out.println(str22); //输出:doog si ++C sihT

StringBuilder字符串变量

 和StringBuffer一样,也是实现SerializableAppendableCharSequence接口。一个可变的字符序列,这个类提供一个与StringBuffer兼容的API,但是不保证同步,该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,比StringBuffer要快。在StringBuilder 上的主要操作是appendinsert方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串生成器中。append方法始终将这些字符添加到生成器的末端;而 insert方法则在指定的点添加字符。将StringBuilder的实例用于多个线程是不安全的。如果需要这样的同步,则建议使用StringBuffer。主要一些操作:

StringBuilder str23 = new StringBuilder("This is");

//StringBuilder后面追加内容

str23.append(" Java");

System.out.println(str23); //输出:This is Java

//删除第6-8个字符

str23.delete(5, 8);

System.out.println(str23); //输出:This Java

//在9个位置插入

str23.insert(9," is good");

System.out.println(str23); //输出:This Java is good

//替换5-9

str23.replace(5, 9, "C++");

System.out.println(str23); //输出:This C++ is good

//倒序

str23.reverse();

System.out.println(str23); //输出:doog si ++C sihT


//变成大写

System.out.println(str23.toString().toUpperCase()); //输出:DOOG SI ++C SIHT


//第一种方案StringBuffer转化成String

String str24 = new String(str23);

System.out.println(str24); //输出:doog si ++C sihT


//第二种方案

String str25 = str23.toString();

System.out.println(str25); //输出:doog si ++C sihT
 
内容概要:本文系统阐述了Java Persistence API(JPA)的核心概念、技术架构、核心组件及实践应用,重点介绍了JPA作为Java官方定义的对象关系映射(ORM)规范,如何通过实体类、EntityManager、JPQL和persistence.xml配置文件实现Java对象与数据库表之间的映射与操作。文章详细说明了JPA解决的传统JDBC开发痛点,如代码冗余、对象映射繁琐、跨数据库兼容性差等问题,并解析了JPA与Hibernate、EclipseLink等实现框架的关系。同时提供了基于Hibernate和MySQL的完整实践案例,涵盖Maven依赖配置、实体类定义、CRUD操作实现等关键步骤,并列举了常用JPA注解及其用途。最后总结了JPA的标准化优势、开发效率提升能力及在Spring生态中的延伸应用。 适合人群:具备一定Java基础,熟悉基本数据库操作,工作1-3年的后端开发人员或正在学习ORM技术的中级开发者。 使用场景及目标:①理解JPA作为ORM规范的核心原理与组件协作机制;②掌握基于JPA+Hibernate进行数据库操作的开发流程;③为技术选型、团队培训或向Spring Data JPA过渡提供理论与实践基础。 阅读建议:此资源以理论结合实践的方式讲解JPA,建议读者在学习过程中同步搭建环境,动手实现文中示例代码,重点关注EntityManager的使用、JPQL语法特点以及注解配置规则,从而深入理解JPA的设计思想与工程价值。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值