String、StringBuffer、StringBuilder

String、StringBuffer、StringBuilder

String的基本知识点

1.String直接继承Object
2.是java.lang包,所以不需要导包
3.使用final修饰,所以不能被继承
4.字符串的内容创建之后不能更改
5.String是引用数据类型,不是基本的数据类型

创建String对象方法

1.直接使用字面量
2.使用new构造方法

使用字面量创建String类型变量
     String s1 = "hello";
     String s2 = s1 + "world";
使用构造方法创建

new String() 创建一个没有值的字符串对象
new String(String original) 使用指定的字符串的值创建一个新的字符串对象
new String(byte[] bytes) 一般是用来将字节数组转换为字符串
new String(char[] chars) 一般是用来将字符数组转换为字符串

        String s1 = new String("hello");
        String s2 = new String("world");
        String s3 = s1 + s2;
注意事项

字符串变量的拼接,是创建一个新对象
字面量的拼接,直接将+优化掉

字符串常量池

字符串类型的值,为了提高复用性,避免开辟多块空间存储相同字符串,节省内存,就设计了一个叫做字符串常量池的内存空间,存在于堆内存中,在创建字符串时,JVM会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。

字符串常量在常量池中位置
        String s1 = new String("hello");
        String s2 = new String("world");
    

在这里插入图片描述
这里简单解释一下堆和栈;在JVM内存中,栈内存存放基本类型的变量和对象的引用变量,堆内存里面存放new创建的对象和数组

String常用方法

toString:String类重写了toString方法,重写的方式:返回字符串的值
equals:String类重写了equals方法,重写的方式:比较两个字符串的值

获取相关

length :获取字符串的长度
charAt(int index):取出指定索引的字符 返回类型为char
indexOf(字符/字符串,int fromIndex):从指定索引开始查找指定字符/字符串的位置

判断相关

equals:判断两个字符串的值是否相等
equalsIgnoreCase:忽略大小写判断两个字符串的值是否相等
contains(String str):判断当前字符串是否包含指定字符串
endsWith(String str):判断当前字符串是否以指定字符串结尾
startsWith(String str):判断当前字符串是否以指定字符串开始
isEmpty():判断是否为空字符串

 		String s1 = "AbCdE";
        String s2 = "abcde";
        System.out.println(s1.equals(s2));//false
        System.out.println(s1.equalsIgnoreCase(s2));//true
        //contains(String str):判断当前字符串是否包含指定字符串
        System.out.println(s1.contains("cde"));//false
        System.out.println(s2.contains("cde"));//true
        //endsWith(String str):判断当前字符串是否以指定字符串结尾
        //startsWith(String str):判断当前字符串是否以指定字符串开始
        s1 = "Xxx.png";
        s2 = ".png";
        System.out.println(s1.endsWith(s2));//true
        System.out.println(s1.startsWith("Xxx"));//true

        String s3 = " ";
        System.out.println(s3.isEmpty());
        
转换相关

toLowerCase () :将字符串转换为全小写

toUpperCase() :将字符串转换为全大写

valueOf(多种类型):将参数转换为String

注意:valueOf是静态方法,所以可以直接使用String类名来调用

其他方法

trim() : 取出字符串前面与后面的空格

replace(old, new) :使用新的字符/字符串 替换 旧的字符/字符串

contact :拼接字符串

注意事项:String的值不能被修改的,所谓的转换、去空格等操作,实际上创建了一个新的String对象作为返回值。所以必须重新去接收。
String s = "AbCdE";
s = s.toLowerCase();//必须再去接收它

String 相关

字符型常量和字符串常量的区别

1.形式上:字符常量是单引号引起的一个字符 字符串常量是双引号引起的多个字符
2.含义上:字符常量相当于一个整型值(ASCII值),可以参加表达式运算 字符串常量代表一个地址值
3.占内存大小 字符常量只占一个字节 字符串常量占若干个字节

String有哪些特性

1.不变性:String是只读字符串,对它进行任何操作,其实都是创建一个新的对象,再把引用指向该对象。不变模式的主要作用在于当一个对象需要被多线程共享并频繁访问时,可以保证数据的一致性。
2.常量池优化:String对象创建之后,会在字符串常量池中进行缓存,如果下次创建同样的对象时,会直接返回缓存的引用
3.final:使用final来定义String类,表示String类不能被继承,提高了系统的安全性

String的不可变性
String为什么是不可变的

String类利用了final修饰的char类型数组存储字符
源码:

/** The value is used for character storage. */
private final char value[];
String是否真的不可变

这个问题就跟讨论java是否真的跨平台

1.String不可变但不代表引用不可以变
String str = "Hello";
str = str + " World";
System.out.println("str=" + str);//输出:str=Hello World

实际上,String的内容是不变的,str不是对象,只是地址引用的指向,只是str由原来指向"Hello"的内存地址转为指向"Hello World"的内存地址而已,也就是说多开辟了一块内存区域给"Hello World"字符串

在这里插入图片描述

2.通过反射是可以修改所谓的"不可变"对象
// 创建字符串"Hello World", 并赋给引用s
String s = "Hello World";

System.out.println("s = " + s); // Hello World

// 获取String类中的value字段
Field valueFieldOfString = String.class.getDeclaredField("value");

// 改变value属性的访问权限
valueFieldOfString.setAccessible(true);

// 获取s对象上的value属性的值
char[] value = (char[]) valueFieldOfString.get(s);

// 改变value所引用的数组中的第5个字符
value[5] = '_';

System.out.println("s = " + s); // Hello_World

通过反射的getDeclaredField可以访问私有成员,然后反射出String对象中的value属性,进而改变通过获得value引用改变数组的结构

String str="i"与String str=new String(“i”)不一样

再次强调 str只是地址的引用 并非对象 前面说到创建String对象的两种方式,虽然这样创建的值都相同,但是内存的分配方式不同。String str="i"的方式,java虚拟机将其分配到常量池;而new String(“i”)则会被分到堆内存中

String str1="i";
String str2=new String("i");

在这里插入图片描述

String str=new String(“xyz”);创建了几个字符串对象

两个对象,一个是常量池中的"xyz",一个是用new创建在堆上的对象;所以为了节省内存,推荐使用String str="…";
在这里插入图片描述

StringBuffer

1.使用final修饰
2.也是一个字符串
3.值是可以修改的(在原地址,改变后并没有新创建对象)

创建对象

不能使用字面量的方式直接创建对象,只能使用构造方法的方式创建

构造方法

StringBuffer() 创建一个空字符串,但是底层维护的数组的长度为16
StringBuffer(String str) 创建一个指定不可变长字符串内容的可变长字符串

常用方法

append(多种类型):将参数的值追加到当前字符串中

insert(int offset,多种类型的值):向字符串的指定位置添加内容

deleteCharAt(int index):删除指定索引处的元素

delete(int start,int end):删除指定索引范围内的元素

reverse():将字符串的内容倒序

StringBuffer与String类型转换

StringBuffer 转换为String:sb.toString()

String转换为StringBuffer:new StringBuffer(String str)

String和 StringBuffer 、StringBuilder的区别

可变性

String类中使用字符数组保存字符串,private final char value[],所以String对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的

线程安全性

String中的对象是不可变的,也就理解为常量,线程安全:AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

性能

每次对String类型进行改变的时候,都会生成一个新的String对象,然后将引用指向新的String对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

对于三者使用的总结

如果要操作少量的数据用String
单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

补充:在使用HashMap的时候,用String做key有什么好处?

HashMap内部实现是通过key的hashcode来确定value的存储位置,因为字符串是不可变的,所以当创建字符串时,它的hahcode被缓存下来,不需要再次计算,所以相比于其他对象更快

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值