【Java】String、StringBuffer、StringBuilder
java.lang.String类
概述
String
:代表字符串。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现
- String声明为final,不可被继承
- 字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
- String实现了Serializable接口:表示字符串是支持序列化的。
- 实现了Comparable接口:表示String可以比较大小
- String内部定义了
private final char[] value
用于存储字符串数据 - 通过字面量的方式(区别于用
new String()
给字符串赋值),此时的字符串值声明在字符串常量池中)。 - 字符串常量池中是不会存储相同内容(使用String类的
equals()
比较)的字符串的。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
String的不可变 性
- 当对字符串重新赋值时,需要重新指定内存区域赋值
- 当对现在的字符串进行连接操作时,也需要重新指定内存区域赋值
- 当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
总结就是只要字符串值有更改,都需要重新指定内存区域赋值。若新值在内存区域已存在,则直接指向该区域,若没有则重新开辟空间
String对象的创建
建议去看API,以下展示集几种常用的
//字面量方式
String str = "hello";
//本质上this.value = new char[0];
String s1 = new String();
//this.value = s.value;
String s2 = new String(String s);
//this.value = Arrays.copyOf(value, value.length);
String s3 = new String(char[] a);
//从字符数组a的startIndex位置截取count个字符
String s4 = new String(char[] a,int startIndex,int count);
从上面代码可以看出String实例化主要有两种方式
- 方式一:通过字面量定义的方式
- 方式二:通过new + 构造器的方式
//通过字面量定义的方式:此时的s1和s2的数据声明在方法区中的字符串常量池中。
String s1 = "javaEE";
String s2 = "javaEE";
//通过new + 构造器的方式:此时的s3和s4保存的是地址值,指向堆空间中的数据。
String s3 = new String("javaEE");
String s4 = new String("javaEE");
System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println(s3 == s4);//false
面试题
String s = new String("abc");方式创建对象,在内存中创建了几个对象?
答:两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:"abc"String str1 = "abc" 与 String str2 = new String("abc");的区别?
字符串拼接方式赋值的对比
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
String s9 = s1 + s2;
System.out.println(s3 == s4);//true
System.out.println(s3 == s5);//false
System.out.println(s3 == s6);//false
System.out.println(s3 == s7);//false
System.out.println(s5 == s6);//false
System.out.println(s5 == s7);//false
System.out.println(s6 == s7);//false
System.out.println(s7 == s9);//false
String s8 = s6.intern();//返回值得到的s8使用的常量值中已经存在的“javaEEhadoop”
System.out.println(s3 == s8);//true
****************************
String s1 = "javaEEhadoop";
String s2 = "javaEE";
String s3 = s2 + "hadoop";
System.out.println(s1 == s3);//false
final String s4 = "javaEE";//s4:常量
String s5 = s4 + "hadoop";
System.out.println(s1 == s5);//true
- 常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
- 只要其中一个是变量,结果就在堆中,且不管变量名是否相同开辟的空间都不同。
- 如果拼接的结果调用intern()方法,返回值就在常量池中
- 若变量用final修饰就变成常量
- 下列程序运行结果
public class StringTest {
String str = new String("good");
char[] ch = { 't', 'e', 's', 't' };
public void change(String str, char ch[]) {
str = "test ok";
ch[0] = 'b'; }
public static void main(String[] args) {
StringTest ex = new StringTest();
ex.change(ex.str, ex.ch);
System.out.print(ex.str); //good 不可变性
System.out.println(ex.ch); //best
} }
StringBuffer、StringBuilder
StringBuffer
:可变的字符序列;线程安全的,效率低;底层使用char[]
存储StringBuilder
:可变的字符序列;jdk5.0新增的,线程不安全的,效率高;底层使用char[]
StringBuffer与StringBuilder的内存解析
//以StringBuffer为例:
String str = new String();//char[] value = new char[0];
String str1 = new String("abc");//char[] value = new char[]{'a','b','c'};
StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];底层创建了一个长度是16的数组。
System.out.println(sb1.length());//0
sb1.append('a');//value[0] = 'a';
sb1.append('b');//value[1] = 'b';
StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length() + 16];
System.out.println(sb2.length()); //3
扩容问题
如果要添加的数据长度大于16,那就需要扩容底层的数组。默认情况下,扩容为原来容量的2倍 + 2,同时将原数组中的元素复制到新的数组中。
开发中建议指定长度:
StringBuffer(int capacity
) 或StringBuilder(int capacity)
三者的执行效率
从高到低排列:StringBuilder > StringBuffer > String
String、StringBuffer、StringBuilder三者的对比
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value; //value没有final修饰,可以扩容
int count; //count记录有效字符的个数
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
- StringBuilder 和 StringBuffer可用方法一致
- StringBuilder 和 StringBuffer都继承于AbstractStringBuilder
- StringBuffer之所以是线程安全的,是因为方法用
synchronized
修饰- StringBuilder 和 StringBuffer 支持链式调用
StringBuffer类不同于String,其对象必须使用构造器生成。有三个构造器
StringBuffer() //初始容量为16的字符串缓冲区
StringBuffer(int size) //构造指定容量的字符串缓冲区
StringBuffer(String str) //将内容初始化为指定字符串内容
StringBuffer 和 StringBuilder的常用方法
StringBufferappend(xxx) //提供了很多的append()方法,用于进行字符串拼接
StringBufferdelete(int start,int end) //删除指定位置的内容
StringBufferreplace(intstart,intend,Stringstr) //把[start,end)位置替换为str
StringBufferinsert(int offset,xxx) //在指定位置插入xxx
StringBufferreverse() //把当前字符序列逆转
【Java】String、StringBuffer、StringBuilder的更多相关文章
- 【37】String,StringBuffer,StringBuilder区别和概念
基本的概念: 查看 API 会发现,String.StringBuffer.StringBuilder 都实现了 CharSequence 接口,内部都是用一个char数组实现,虽然它们都与字符串相关 ...
- 【Java】String和Date、Timestamp之间的转换
首先,定义一个Format的日期格式: SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 一.S ...
- Java学习——String,StringBuffer和StringBuilder
Java学习——String,StringBuffer和StringBuilder 摘要:本文主要介绍了String字符串在内存中的存储情况,以及StringBuffer和StringBuilder的 ...
- 认识Java中String与StringBuffer以及StringBuilder
String(引用数据类型) String对象一经创建就不会发生变化(在常量池里),即便是赋予新的值,也不是在原来的基础上改变,而是创建一个新的字符串对象,将引用指向这个对象,会造成空间的浪费: St ...
- 【Java】String、StringBuilder和StringBuffer
[String] 首先,从String类的定义入手,可以看到String类是由final修饰,即不可变的,一旦创建出来就不可修改,因此首先明确,字符串的拼接.截取等操作都会产生新的字符串对象. 观察以 ...
- 【java】学习路径17-StringBuffer、StringBuilder的使用与区别
本文讲解StringBuffer和StringBuilder的使用与区别. 1-- String String类型我们已经很熟悉了,String一旦被赋值,其在堆中的数据便无法修改. 平时我们的&qu ...
- 【Java】运算符(算术、赋值、比较(关系)、逻辑、条件、位运算符)
运算符 文章目录 运算符 1. 算术运算符 2. 赋值运算符 3. 比较运算符 4. 逻辑运算符 5. 条件运算符 6. 位运算符 7. 运算符优先级 8. 运算符操作数类型说明 9.code 算术运 ...
- 【java】String类和StringBuffer类常用操作
String类是字符串常量,是不可更改的常量.而StringBuffer是字符串变量,它的对象是可以扩充和修改的.StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于Stri ...
- 【java】String类常见操作
秋招做题需要,总结String类常用api如下: 简单的:str.length().str.isEmpty().str.split(“;”)切割 1.字符串反转:借助StringBuilder/Str ...
随机推荐
- kubelet源码分析——kubelet简介与启动
kubelet是k8s集群中一个组件,其作为一个agent的角色分布在各个节点上,无论是master还是worker,功能繁多,逻辑复杂.主要功能有 节点状态同步:kublet给api-server同 ...
- Dapr + .NET Core实战(九)本地调试
前几节开发Dapr应用程序时,我们使用 dapr cli 来启动dapr服务,就像这样: dapr run --dapr-http-port 3501 --app-port 5001 --app-id ...
- excel模板数据填充 :tablefill
背景(问题) 在Web后台系统中或多或少都存在导入数据的功能,其中操作流程基本是 1.下载模板 2.填充模板数据 3.上传模板 但通常比较耗费时间的是填充模板数据这一步骤, 已自己为例之前的数据要么是 ...
- Java泛型中的细节
Java泛型中的细节 如果没有泛型 学习Java,必不可少的一个过程就是需要掌握泛型.泛型起源于JDK1.5,为什么我们要使用泛型呢?泛型可以使编译器知道一个对象的限定类型是什么,这样编译器就可以在一 ...
- 【UE4 C++ 基础知识】<3> 基本数据类型、字符串处理及转换
基本数据类型 TCHAR TCHAR就是UE4通过对char和wchar_t的封装 char ANSI编码 wchar_t 宽字符的Unicode编码 使用 TEXT() 宏包裹作为字面值 TCHAR ...
- VS Code C/C++开发环境配置
VS Code C/C++开发环境配置 一.安装 1.前往官网下载安装即可 https://code.visualstudio.com/ 2.进入VS Code安装如下插件 二.C/C++开发 ...
- UML图 | 时序图(顺序、序列图)绘制
上一次写过一篇 UML | 类图 相关的文章,平时规范开发会用的上,或者是写什么文档,就还是需要画图,就像毕业设计就是如此.希望能够帮助到大家. 注:本文中所用画图软件为 Microsoft Visi ...
- 服务器端的GPU使用
服务器端的GPU使用 查看GPU信息 查看nvidia GPU信息: # 输入指令 lspci | grep -i nvidia # 结果如下: # 04:00.0 3D controller: NV ...
- mysqld_exporter监控mysql信息
mysqld_exporter监控mysql信息 一.背景 二.prometheus接入mysqld_exporter 1.安装mysqld_exporter 2.创建mysqld_exporter用 ...
- python读取、写入txt文本内容
转载:https://blog.csdn.net/qq_37828488/article/details/100024924 python常用的读取文件函数有三种read().readline().r ...