字符串相关类之不可变字符序列:String
String的特性
-
java.lang.String
类代表字符串。Java程序中所有的字符串文字(例如"hello"
)都可以看作是实现此类的实例。 -
字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
-
字符串String类型本身是final声明的,意味着我们不能继承String。
-
String对象的字符内容是存储在一个字符数组value[]中的。
"abc"
等效于char[] data={'h','e','l','l','o'}
。//jdk8中的String源码: public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; //String对象的字符内容是存储在此数组中 /** Cache the hash code for the string */ private int hash; // Default to 0
-
private意味着外面无法直接获取字符数组,而且String没有提供value的get和set方法。
-
final意味着字符数组的引用不可改变,而且String也没有提供方法来修改value数组某个元素值
-
因此字符串的字符数组内容也不可变的,即String代表着不可变的字符序列。即,一旦对字符串进行修改,就会产生新对象。
-
JDK9只有,底层使用byte[]数组。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { @Stable private final byte[] value; } //官方说明:... that most String objects contain only Latin-1 characters. Such characters require only one byte of storage, hence half of the space in the internal char arrays of such String objects is going unused. //细节:... The new String class will store characters encoded either as ISO-8859-1/Latin-1 (one byte per character), or as UTF-16 (two bytes per character), based upon the contents of the string. The encoding flag will indicate which encoding is used.
-
-
Java 语言提供对字符串串联符号(“+”)以及将其他对象转换为字符串的特殊支持(toString()方法)。
String str1 = “abc”; 与 String str2 = new String(“abc”);的区别?
str2 首先指向堆中的一个字符串对象,然后堆中字符串的value数组指向常量池中常量对象的value数组。
字符串常量存储在字符串常量池,目的是共享。
字符串非常量对象存储在堆中。
String str2 = new String(“hello”); 在内存中创建了2个对象。
intern()
- String s1 = “a”;
说明:在字符串常量池中创建了一个字面量为"a"的字符串。
- s1 = s1 + “b”;
说明:实际上原来的“a”字符串对象已经丢弃了,现在在堆空间中产生了一个字符串s1+“b”(也就是"ab")。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能。
- String s2 = “ab”;
说明:直接在字符串常量池中创建一个字面量为"ab"的字符串。
- String s3 = “a” + “b”;
说明:s3指向字符串常量池中已经创建的"ab"的字符串。
- String s4 = s1.intern();
说明:堆空间的s1对象在调用intern()之后,会将常量池中已经存在的"ab"字符串赋值给s4。
String s1 = "hello";
String s2 = "world";
String s3 = "hello" + "world";
String s4 = s1 + "world";
String s5 = s1 + s2;
String s6 = (s1 + s2).intern();
System.out.println(s3 == s4);//false
System.out.println(s3 == s5);//false
System.out.println(s4 == s5);//false
System.out.println(s3 == s6);//true
结论:
(1)常量+常量:结果是常量池。且常量池中不会存在相同内容的常量。
(2)常量与变量 或 变量与变量:结果在堆中
(3)拼接后调用intern方法:返回值在常量池中
String str = "hello";
String str2 = "world";
String str3 ="helloworld";
String str4 = "hello".concat("world");
String str5 = "hello"+"world";
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
concat方法拼接,哪怕是两个常量对象拼接,结果也是在堆。
String的常用API-1
构造器
public String()
:初始化新创建的 String对象,以使其表示空字符序列。String(String original)
: 初始化一个新创建的String
对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。public String(char[] value)
:通过当前参数中的字符数组来构造新的String。public String(char[] value,int offset, int count)
:通过字符数组的一部分来构造新的String。public String(byte[] bytes)
:通过使用平台的默认字符集解码当前参数中的字节数组来构造新的String。public String(byte[] bytes,String charsetName)
:通过使用指定的字符集解码当前参数中的字节数组来构造新的String。
String与其他结构间的转换
字符串 --> 基本数据类型、包装类:
- Integer包装类的public static int parseInt(String s):可以将由“数字”字符组成的字符串转换为整型。
- 类似地,使用java.lang包中的Byte、Short、Long、Float、Double类调相应的类方法可以将由“数字”字符组成的字符串,转化为相应的基本数据类型。
基本数据类型、包装类 --> 字符串:
- 调用String类的public String valueOf(int n)可将int型转换为字符串
- 相应的valueOf(byte b)、valueOf(long l)、valueOf(float f)、valueOf(double d)、valueOf(boolean b)可由参数的相应类型到字符串的转换。
字符数组 --> 字符串:
- String 类的构造器:String(char[]) 和 String(char[],int offset,int length) 分别用字符数组中的全部字符和部分字符创建字符串对象。
字符串 --> 字符数组:
-
public char[] toCharArray():将字符串中的全部字符存放在一个字符数组中的方法。
-
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):提供了将指定索引范围内的字符串存放到数组中的方法。
字符串 --> 字节数组:(编码)
- public byte[] getBytes() :使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
- public byte[] getBytes(String charsetName) :使用指定的字符集将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。
字节数组 --> 字符串:(解码)
- String(byte[]):通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
- String(byte[],int offset,int length) :用指定的字节数组的一部分,即从数组起始位置offset开始取length个字节构造一个字符串对象。
- String(byte[], String charsetName ) 或 new String(byte[], int, int,String charsetName ):解码,按照指定的编码方式进行解码。
String的常用API-2
String
类包括的方法可用于检查序列的单个字符、比较字符串、搜索字符串、提取子字符串、创建字符串副本并将所有字符全部转换为大写或小写。
系列1:常用方法
(1)boolean isEmpty():字符串是否为空
(2)int length():返回字符串的长度
(3)String concat(xx):拼接
(4)boolean equals(Object obj):比较字符串是否相等,区分大小写
(5)boolean equalsIgnoreCase(Object obj):比较字符串是否相等,不区分大小写
(6)int compareTo(String other):比较字符串大小,区分大小写,按照Unicode编码值比较大小
(7)int compareToIgnoreCase(String other):比较字符串大小,不区分大小写
(8)String toLowerCase():将字符串中大写字母转为小写
(9)String toUpperCase():将字符串中小写字母转为大写
(10)String trim():去掉字符串前后空白符
(11)public String intern():结果在常量池中共享
系列2:查找
(11)boolean contains(xx):是否包含xx
(12)int indexOf(xx):从前往后找当前字符串中xx,即如果有返回第一次出现的下标,要是没有返回-1
(13)int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
(14)int lastIndexOf(xx):从后往前找当前字符串中xx,即如果有返回最后一次出现的下标,要是没有返回-1
(15)int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。
系列3:字符串截取
(16)String substring(int beginIndex) :返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
(17)String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
系列4:和字符/字符数组相关
(18)char charAt(index):返回[index]位置的字符
(19)char[] toCharArray(): 将此字符串转换为一个新的字符数组返回
(20)static String valueOf(char[] data) :返回指定数组中表示该字符序列的 String
(21)static String valueOf(char[] data, int offset, int count) : 返回指定数组中表示该字符序列的 String
(22)static String copyValueOf(char[] data): 返回指定数组中表示该字符序列的 String
(23)static String copyValueOf(char[] data, int offset, int count):返回指定数组中表示该字符序列的 String
系列5:开头与结尾
(24)boolean startsWith(xx):测试此字符串是否以指定的前缀开始
(25)boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始
(26)boolean endsWith(xx):测试此字符串是否以指定的后缀结束
系列6:替换
(27)String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。 不支持正则。
(28)String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
(29)String replaceAll(String regex, String replacement):使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
(30)String replaceFirst(String regex, String replacement):使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
字符串相关类之可变字符序列:StringBuffer、StringBuilder
因为String对象是不可变对象,虽然可以共享常量对象,但是对于频繁字符串的修改和拼接操作,效率极低,空间消耗也比较高。因此,JDK又在java.lang包提供了可变字符序列StringBuffer和StringBuilder类型。
- java.lang.StringBuffer代表
可变的字符序列
,JDK1.0中声明,可以对字符串内容进行增删,此时不会产生新的对象。 - StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且提供相关功能的方法也一样。
- 区分String、StringBuffer、StringBuilder
- String:不可变的字符序列; 底层使用char[]数组存储(JDK8.0中)
- StringBuffer:可变的字符序列;线程安全(方法有synchronized修饰),效率低;底层使用char[]数组存储 (JDK8.0中)
- StringBuilder:可变的字符序列; jdk1.5引入,线程不安全的,效率高;底层使用char[]数组存储(JDK8.0中)
StringBuilder、StringBuffer的API
StringBuilder、StringBuffer的API是完全一致的,并且很多方法与String相同。
1、常用API
(1)StringBuffer append(xx):提供了很多的append()方法,用于进行字符串追加的方式拼接
(2)StringBuffer delete(int start, int end):删除[start,end)之间字符
(3)StringBuffer deleteCharAt(int index):删除[index]位置字符
(4)StringBuffer replace(int start, int end, String str):替换[start,end)范围的字符序列为str
(5)void setCharAt(int index, char c):替换[index]位置字符
(6)char charAt(int index):查找指定index位置上的字符
(7)StringBuffer insert(int index, xx):在[index]位置插入xx
(8)int length():返回存储的字符数据的长度
(9)StringBuffer reverse():反转
当append和insert时,如果原来value数组长度不够,可扩容。
如上(1)(2)(3)(4)(9)这些方法支持
方法链操作
。原理:
2、其它API
(1)int indexOf(String str):在当前字符序列中查询str的第一次出现下标
(2)int indexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的第一次出现下标
(3)int lastIndexOf(String str):在当前字符序列中查询str的最后一次出现下标
(4)int lastIndexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的最后一次出现下标
(5)String substring(int start):截取当前字符序列[start,最后]
(6)String substring(int start, int end):截取当前字符序列[start,end)
(7)String toString():返回此序列中数据的字符串表示形式
(8)void setLength(int newLength) :设置当前字符序列长度为newLength