1.String类
1.1String的特性
<1>String:字符串,使用一对""引起来表示。它们的值在创建后不能更改;
<2>String声明为final的,不可被继承;
<3>String实现了Serializable接口:表示字符串是支持序列化的;实现了Comparable接口:表示String可以比较大小;
<4>String内部定义了final char[] value用于存储字符串数据。
1.2理解String的不可变性
<1>当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值;
<2>当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值;
<3>当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
1.3String实例化的不同方式
<1>理解两种实例化方式:
方法1):通过字面量定义的方式:String str1="abc";
(通过字面量定义的方式:此时s1的数据"abc"声明在方法区中的字符串常量池中)
方法2):通过new+构造器的方式:String str2=new String("abc");
(通过new+构造器定义的方式:此时的s3保存的地址值,是数据在堆空间中开辟空间以后对应的地址值)
<2>一个问题:用String s=new String("abc")方式创建对象时,在内存中创建了几个对象?
答:两个,一个是在堆空间中new的结构,另一个是在cher[] value对应的常量池中的数据"abc"
1.4字符串拼接方式赋值的对比
<1>常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量;
<2>只要其中一个是变量,结果就在堆中;
<3>如果拼接的结果调用intern()方法,返回值就在常量池中。
String s1 = "javaEE";//指向常量池
String s2 = "hadoop";//指向常量池
String s3 = "javaEEhadoop";//指向常量池
String s4 = "javaEE" + "hadoop";//为常量与常量拼接,指向常量池
String s5 = s1 + "hadoop";//s1为变量,指向堆
String s6 = "javaEE" + s2;//s2为变量,指向堆
String s7 = s1 + s2;//s1,s2为变量,指向堆
//注意:常量值池相同的字符串常量只有一份,而堆中是new一个则新增一个
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 = s6.intern();//返回值得到的s8使用的是常量池中已经存在的“javaEEhadoop”
System.out.println(s3 == s8);//true
//当然,定义一个常量对象与字符串常量拼接,也是指向常量池的,如下代码:
String s9 = "javaEEhadoop";
final String s10 = "javaEE";//s10:是常量
String s11 = s10 + "hadoop";
System.out.println(s1 == s5);//true
1.5例题(涉及值传递和String的不变性)
public class TestQQQ{
String str = new String("good");
char[] ch = { 't', 'e', 's', 't' };
public void change(String s, char cs[]) {
s = "test ok";
cs[0] = 'b';
}
public static void main(String[] args) {
TestQQQ ex = new TestQQQ();
System.out.println(ex.str );//输出good
System.out.println(ex.ch);//输出test
ex.change(ex.str, ex.ch);
System.out.println(ex.str );//输出good
System.out.println(ex.ch);//输出best
}
}
为什么这里在调用了自定义类的方法change()后, 对象的str属性没有发生变化呢?
分析:在之前,我可能会这样分析,因为String是引用类型,引用类型做形参,如果形参在方法体内有改变,那么实参也会做相应的改变,所以认为当前的TestQQQ类的对象ex的str值变为了"test ok",但其实这句话不适用所有情况,此处便是一个特例,原因就是因为String对象的不可变性。更应该记住的参数传递的结论是:引用类型形参传递的是地址值,基本数据类型传递的是数据值(这个结论是永远正确的)。
1.6JVM中涉及字符串的内存结构
<1>jdk 1.6 (jdk 6.0 ,java 6.0):字符串常量池存储在方法区(永久区);
<2>jdk 1.7:字符串常量池存储在堆空间;
<3>jdk 1.8:字符串常量池存储在方法区(元空间)。
1.7String类中常用的方法
方法 | 释义 |
int length() | 返回字符串的长度:return value.length |
char charAt(int index) | 返回某索引处的字符:return value[index] |
boolean isEmpty() | 判断是否是空字符串:return value.length==0 |
String toLowerCase() | 将String中的所有字符转换为小写,注意,此字符串本身不会变(因为String的不变性),一般左侧有一个变量接受转换后的字符串 |
String toUpperCase() | 将String中的所有字符转换为大写,注意,此字符串本身不会变(因为String的不变性),一般左侧有一个变量接受转换后的字符串 |
String trim() | 返回字符串的副本,忽略前导空白和尾部空白 |
boolean equals(Object obj) | 比较字符串的内容是否相同 |
boolean equalsIgnoreCase(String anotherString) | 与equals方法类似,但该方法忽略大小写 |
String concat(String str) | 将指定字符串str连接到此字符串的结尾,等价于用“+” |
int compareTo(String anotherString) | 比较两个字符串的大小,若为正数,表示当前对象大;为负数反之 |
String substring(int beginIndex) | 返回一个新的字符串,它是此字符串的从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) | 使用指定的字面值替换序列(replacement)替换当前字符串(target)所匹配字面值目标序列的子字符串 |
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个,如果超过了,剩下的全部都放到最后一个元素中 |
额外补充:
<2>String join()方法:
返回使用指定分隔符拼接一个字符串。在join() 方法中,为每个元素添加了分隔符。如果为null元素,则添加“null”。
关于StringBuilder类的常用方法:StringBuilder常用方法