String、StringBuffer、StringBuilder类

1、String类概述:

String:字符串,使用一对“”来表示。

(1)String声明为final的,不可被继承

(2)String实现了Serializable接口,表示字符串是支持序列化的。

   String实现了Comparable接口,表示String可以比较大小。

(3)String内部定义了final char[] value ,用于存储字符数据。

(4)String代表是不可变的字符序列。称为:不可变特性

体现如下:

① 当对字符串重新赋值时,需要重新指定内存区域赋值,不能使用原有的value进行赋值。

② 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。

③ 当调用String的replace()方法修改指定的字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。

(5)通过字面量的方式(区别于new方式)给一个字符串赋值,此时的字符串值声明在字符串常量池中。

(6)字符串常量池中是不会存储相同内容的字符串的。

2、String不同实例化方式对比:

方式1:通过字面量定义:此时的变量中的数据声明在方法区中的字符串常量池中。

例如:String s1 = "a";

方式2:通过 new + 构造器:此时的变量中保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。

例如:String s2 = new String("b");

面试题5:“String s2 = new String("c");” 方式创建对象,在内存中创建了几个对象?

两个,一个是堆空间中的 new 结构,另一个是 char[] 数组对应的常量池中的数据:"c"。

3、String不同拼接操作的对比:

例如:

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;

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

String s8 = s5.intern();//intern()方法的返回值得到的 “s8”,使用的是常量池中已经存在的数据“javaEEhadoop”
System.out.println(s3 == s8); //结果:true

结论:

① 常量与常量的拼接结果是在常量池中。且常量池中不会存在相同内容的常量;

② 只要其中有一个是变量,结果就在堆中;

③ 如果拼接的结果调用intern()方法,返回值就在常量池中。

4、JVM中涉及字符串的内存结构:

(1)JVM(Java虚拟机)有三种,分别是:

SUN公司的HotSpot

BEA公司的JRockit

IBM公司的J9VM

注意:通常情况下,默认使用HotSpot。

(2)从规范上来说,堆(Heap)分为三部分,分别是:

新生区(Young Generation Space):简称 Young

养老区(Tenure Generation Space):简称 Old

永久存储区(Permanent Space):简称 Perm,也可以说是:方法区

注意:一般情况下,方法区是单独的一块空间。

(3)字符串常量池,在每个JDK版本中,位置也不同:

JDK1.6(6.0)及其以前,字符串常量池是在方法区中,具体实现是 永久代;

JDK1.7(7.0)中,字符串常量池又划分到 堆(Heap)中;

JDK1.8(8.0)及其以后,字符串常量池又归回到方法区中,此时具体实现变为 元空间。

5、String类的常用方法:

int length():返回字符串长度

char charAt(int index):返回某索引处的字符

boolean isEmpty():判断是否是空字符串

String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写

String toUpperCase():使用默认语言环境,将 String 中的所有字符转换为大写

String trim():返回字符串的副本,忽略前导空白和尾部空白

boolean equals(Object obj):比较字符串内容是否相同

boolean equalsIgnoreCase(String anotherString):与equals()方法类似,忽略大小写

String concat(String str):将指定字符串连接到此字符串的结尾(等同于用 “+”)

int compareTo(String anotherString):比较两个字符串大小

String subString(int beginIndex):返回一个新字符串,它是此字符串从 beginIndex 位置开始截取的

String subString(int beginIndex, int endIndex):返回一个新字符串,它是此字符串从 beginIndex 位置开始,到 endIndex 位置结束截取的

boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束

boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始

boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定的前缀开始

boolean contains(CharSequence s):当且仅当此字符串包含指定的char值序列时,返回true

int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引

int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始

int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引

int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索

注意:indexOf 和 lastIndexOf 方法,如果未找到都是返回 -1。

String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。

String replace(charSequence target, charSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串

String replaceAll(String regex, String replacement):使用给定的replacement替换此字符串所有匹配给定的正则表达式的子字符串

String replaceFirst(String regex, String replacement):使用给定的replacement替换此字符串匹配给定的正则表达式的第一个子字符串

boolean matches(String regex):告知此字符串是否匹配给定的正则表达式

String[] split(String regex):根据给定正则表达式的匹配拆分此字符串

String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中

6、String类与char[]数组直接的转换:

(1)String → char[]:调用 String 的 toCharArray() 方法

(2)char[] → String:调用 String 的 构造器

7、String类与byte[]数组直接的转换:

(1)String → byte[]:调用 String 的 getBytes() 方法(此方法可以指定字符集编码)

(2)byte[] → String:调用 String 的 构造器

特别说明:编码和解码时,编码集必须一致,否则会出现乱码。

8、StringBuffer和StringBuilder的使用:

(1)String、StringBuffer和StringBuilder的异同:

不同点:

String:不可变的字符序列;

StringBuffer:可变的字符序列,线程安全的,效率低;

StringBuilder:可变的字符序列,JDK5.0新增的,线程不安全的,效率高。

相同点:都是操作字符串的类,底层都是使用char[]数组存储的。

9、StringBuffer的源码分析(StringBuilder与之相同):

String s = new String("abc"); //char[] value = new char[]{'a','b','c'};

StringBuffer sb = new StringBuffer(); //char[] value = new char[16];底层创建了一个长度是16的char[]数组

问题1:用StringBuffer创建一个实例对象时,在创建时没有添加数据,此时该实例对象的长度是:0 (并不是底层默认的16)

问题2:扩容问题:如果要添加的数据在底层数组里放不下了,那就需要扩充底层的数组。默认情况下,扩容为原来容量的2倍+2,同时将原有数组中的元素复制到新的数组中。

指导意义:开发中建议使用 StringBuffer(int capacity) 或 StringBuilder(int capacity) 构造器(此种构造器需指定长度,避免扩容)

10、StringBuffer的常用方法(StringBuilder与之相同):

StringBuffer append():提供了很多的append()方法,用于进行字符串拼接

StringBuffer delete(int start, int end):删除指定位置的内容

StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str

StringBuffer insert(int offset, XXX):在指定位置插入XXX

StringBuffer reverse():把当前字符序列逆转

int indexOf(String str):返回当前子字符串在原字符串中的索引位置,没找到返回-1

String subString(int start, int end):返回一个从start开始到end索引结束的左闭右开区间的子字符串

int length():获取字符串长度

char charAt(int n):

void setCharAt(int n, char ch):

总结(常用方法分类):

① 增加:append()

② 删除:delete(int start, int end)

③ 修改:setCharAt(int n, char ch) 和 replace(int start, int end, String str)

④ 查询:charAt(int n)

⑤ 插入:insert(int offset, XXX)

⑥ 长度:length()

⑦ 遍历:for() + charAt() 或 toString()

11、String、StringBuffer、StringBuilder的效率对比:

从高到低排序:StringBuilder > StringBuffer > String

posted @ 2022-06-22 21:11  萧若風  阅读(22)  评论(0编辑  收藏  举报