String类
String类的介绍
1 什么是String类
String类
是表示字符串的类型,在Java程序中,字符串的值是用双引号标识的,所有字符串的字面值都是String类
的实例,即String对象
。
简单地说,程序中出现的所有用双引号标识的值,即使不是new
出来的,也都是String对象
。
String类
是final
类,即没有子类。
String类
是Serializable
、Comparable
和CharSequence
接口的实现类:
Serializable
接口:意味着String类
是可序列化的,后续会具体学习。Comparable
接口:意味着String类
的实例是可以比较大小的。
String类
中的char
型字符串私有固定属性value
就是用来保存String
对象的数据的,即具体值的,该属性是final
的,意味着虽然String
实例本质上是char型数组,但是该数组不能改变,这就体现了String
实例的不可变性。
2 String实例的不可变性及理解
String
的不可变性体现为,即使是同一个String
型变量,只要对应的String
的数据改变了,该String
对象就改变了,即对应的地址值改变了。普通类型的某个属性值改变了,对应的整个对象是没有变的。String
之所以有不可变性,是因为对于相同常量字符串的String
对象,它们引用的地址值是相同的,不可变性就是确保对一个对象的改变不会影响其他对象的字符串。
String
类的实例化过程的内存结构涉及堆
和方法区
中的字符串常量池
,字符串常量池
中保存的是不重复的常量字符串(即String对象),即可以重用,具体地:
- 以字面量形式实例化
String
类时(此处指的是直接给出字符串常量),相当于直接将一个字符串常量赋值给String
变量,这时就是先在方法区
的字符串常量池
中生成对应的字符串常量对应的字符串对象,如果常量池
中已经存在这个字符串常量,就会直接用已存在的字符串常量,然后将该字符串常量的址值赋值给该String
变量。也就是说,字面量形式实例化的String
类对象,如果字符串相同,实际上对应的对象也是相同的,都是来自于常量池
中的同一个字符串对象。
例如String s = "abc"
,那么如果方法区中的字符串常量池中没有"abc"字符串常量对应的字符串对象,就先在常量池中生成"abc"对应的字符串对象,然后将该地址值赋值给String变量s。 - 以字符串字面值作为参数通过
new
的形式构造String
类实例时,整个过程是构造了两个对象,一方面会为字符串字面值在方法区
中的字符串常量池
中生成对应对象(如果常量池中已存在则直接用已存在的),另一方面在堆
空间中开辟一个对应对象的空间,并且其中包含了字符串对象对应的char型数组属性value
,而value
的值是对应字符串常量的引用,即字符串常量池
中的对应字符串常量的地址。简单地说,以new
的形式构造的String
类实例的地址值是在堆
空间中的,但是其中包含了字符串常量池
中的对应字符串的引用。
例如String s = new String("abc")
,理解为先存在了"abc",此时就会在方法区中的字符串常量池中生成"abc"对应的字符串对象,然后在堆中new
了一个String变量s对应的空间,其中包含的表示字符串值的私有属性value的值就是常量池中"abc"的引用。 - 以字符串变量通过变换后赋值的形式生成
String
类实例时,整个过程并不是先计算好最终确定的字符串的值然后具体地址值取决于确定的值,由于存在变量,不管这个字符串变量的当前的值是什么,当前生成的字符串对象的地址值都是在堆空间,相当于new
出来的,其对应的属性value的值就是对应的字符串变量变换公式当前结果对应的字符串常量在常量池中对应的地址值,有变量就必须通过堆中的属性引用的方式来引用常量池的对应字符串对象,无法直接引用常量池中的对应地址值。注意,用final
修饰的变量就是常量,是常量的字符串,就是可以直接放到常量池中的。
例如String s = s1("abc") + ""
,理解为只要存在变量,在堆中new
出对应s对应的空间,其中包含的表示字符串值的私有属性value的值就是表达式s1 + ""
当前的结果(因为s1是变量有可能会变,所以是当前)对应的字符串在字符串常量池的地址值。
注意,字符串变量直接赋值给另一个字符串变量就要分情况考虑了,因为这种直接赋值是直接给相同的地址值的,如果赋值的变量的地址值是在常量池中的,则被赋值的字符串对应的地址值也是常量池中的。
String
类的对象对应的地址值可能是堆空间中的,也可能是常量池中的,String
类的public String intern()
方法能够返回对应字符串对象的常量池地址值,即对应的在常量池中的字符串对象。
JVM中字符串常量池所在位置说明:
- jdk 1.6(jdk 6.0, java 6.0):字符串常量池位于方法区(永久区);
- jdk 1.7:字符串常量池位于堆空间;
- jdk 1.8:字符串常量池位于方法区(元空间)。
3 String类的构造器
String
类有大量的构造器,具体可以参照对应的官方文档。
常用的String对象创建方法为:
4 面试题
该题本质上考察的是值传递机制,这样理解:
- 方法的形参理解为一个
方法中待赋值的变量名
,这里就是change方法中,定义了两个待赋值的变量str和ch - 传递给方法的实参理解为传递给对应方法形参对应的变量名的值,这里就是给方法中的str传递了属性str的值,即属性对应的地址值,给方法中的ch传递了属性ch的地址值:
str = this.str, ch = this.ch
- 方法中的字符串变量str重新进行了赋值,并不影响属性str,方法中的ch是对其对应地址值的对象进行更改,由于其地址值和属性ch地址值相同,因此相当于修改属性ch。
String类的方法(这里没有列举没学习过的知识相关的方法),具体参照对应官方文档和源码:
public char charAt(int index)
:返回对应字符串对象对应字符串值的指定索引的字符。public int codePointAt(int index)
:返回对应字符串对象对应字符串值的指定索引的字符对应的Unicode码的值。public int codePointBefore(int index)
:返回对应字符串对象对应字符串值的指定索引的字符的前一个字符对应的Unicode码的值。public int compareTo(String anotherString)
:将对应字符串对象与参数字符串对象按照字典顺序比较大小,如果返回负数,则说明按照字典顺序对应字符串对象的字符串值在参数字符串对象的字符串值之前,如果返回正数,则说明按照字典顺序对应字符串对象的字符串值在参数字符串对象的字符串值之后,如果返回0,则说明二者字符串值相等。public int compareToIgnoreCase(String str)
:是compareTo
方法的忽略大小写版本。public String concat(String str)
:返回对应字符串对象末尾拼接上参数字符串对象的字符串值对应的字符串。public boolean contains(CharSequence s)
:判断对应字符串对象中是否包含参数对应的字符串(CharSequence理解为字符串)。public boolean endsWith(String suffix)
:判断对应字符串对象是否以指定字符串为后缀。注意,如果指定字符串为空字符串,返回值为true
。public boolean equals(Object anObject)
:判断对应字符串对象与参数对象的值是否相等,当且仅当参数对象是非null
的String
对象,且其字符串值与对应字符串对象的字符串值完全相同时才会返回true
。public boolean equalsIgnoreCase(String anotherString)
:判断对应字符串对象与参数字符串对象的值是否是不区分大小写的相等。public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
:复制对应字符串到一个字符数组中。参数srcBegin
与srcEnd
表示指定复制字符串的开始和结束位置,左闭右开的效果,参数dst
表示指定的要复制到的字符数组,参数dstBegin
表示指定从目标字符数组的哪个索引位置开始复制。
注意,该方法并不能改变目标字符数组的长度,因此要求复制的目标字符数组的长度要大于或等于dstBegin + (srcEnd-srcBegin)
。简单地说,这个方法可以理解为用字符串替换目标字符数组中的字符。public int indexOf(int ch)
:返回对应字符串对象中指定的字符(或Unicode码对应的字符)第一次出现的索引。public int indexOf(int ch, int fromIndex)
:返回对应字符串对象中从指定位置索引开始指定的字符(或Unicode码对应的字符)第一次出现的索引。如果找不到,返回-1。如果参数fromIndex
是负数,效果与其为0效果一样。如果参数fromIndex
是大于对应字符串的长度的值,效果与其为字符串长度的值一样,返回-1。public int indexOf(String str)
:public int indexOf(int ch)
的字符串版本。public int indexOf(String str, int fromIndex)
:public int indexOf(int ch, int fromIndex)
的字符串版本。public String intern()
:返回对应字符串对象在字符串常量池中对应的字符串对象。public boolean isEmpty()
:判断对应字符串对象的长度是否为0。public int lastIndexOf(int ch)
:public int indexOf(int ch)
方法的从最后一个索引开始找,第一次出现的索引,注意从后面开始找,不代表最后一个索引值是0的意思,仍然是正常的索引值,只是从后开始找而已。public int lastIndexOf(int ch, int fromIndex)
:public int indexOf(int ch, int fromIndex)
方法的从最后一个索引开始的版本。注意,这里是从指定的索引位置开始往前找,意味着如果指定的索引位置为字符串最后一个字符的索引位置,那么可能搜索整个字符串,如果指定的索引位置为字符串的第一个字符的索引位置,那么只可能搜索第一个字符然后结束。public int lastIndexOf(String str)
:public int indexOf(String str)
方法的从最后一个索引开始的版本。public int lastIndexOf(String str, int fromIndex)
:public int indexOf(String str, int fromIndex)
方法的从最后一个索引开始的版本。public int length()
:返回对应字符串对象的字符串长度。public boolean matches(String regex)
:判断对应字符串与参数正则表达式是否匹配。public String replace(char oldChar, char newChar)
:将对应字符串对象中所有的oldChar
都替换为newChar
,返回对应的字符串对象。public String replace(CharSequence target, CharSequence replacement)
:public String replace(char oldChar, char newChar)
方法的字符串版本。public String replaceAll(String regex, String replacement)
:将对应字符串对象中所有与参数regex
对应的正则表达式匹配的子串替换为参数replacement
对应的字符串,返回对应的字符串对象。public String replaceFirst(String regex, String replacement)
:上一个方法的只替换第一个的版本。public String[] split(String regex)
:根据给定的正则表达式字符串来切分对应的字符串,以字符串数组的形式返回切分后的结果。public boolean startsWith(String prefix)
:判断对应字符串是否以指定字符为前缀。public boolean startsWith(String prefix, int toffset)
:判断对应字符串是否从指定位置开始以指定字符串为前缀。public String substring(int beginIndex)
:返回对应字符串从指定位置开始的子串。public String substring(int beginIndex, int endIndex)
:返回对应字符串从指定位置开始到结束位置的子串,不包括结束位置的的字符,左闭右开。public char[] toCharArray()
:返回对应字符串对应的字符数组。public String toLowerCase()
:返回对应字符串中所有字符小写的版本。public String toUpperCase()
:返回对应字符串中所有字符大写的版本。public String trim()
:返回对应字符串去掉首尾空格的版本。public static String valueOf(xxx)
:返回指定参数的字符串版本。public byte[] getBytes()
:返回对应字符串对应的字节码数组形式,等同于将对应字符串进行编码,默认使用当前平台的字符集(IDEA中右下角显示了当前平台使用的字符集)。public byte[] getBytes(String charsetName) throws UnsupportedEncodingException
:返回对应字符串对应的指定字符集的字节码数组形式,等同于将对应字符串在指定字符集进行编码。
对于将字符串转换为char型数组或者byte型数组,逆转换过程使用String构造器即可。将byte型数组转换为字符串,等同于字符串的解码,编码与解码要使用一致的字符集才不会出现乱码情况。