一、String概述
String:,使用一对"",引起来表示
-
String声明为final的,不可被继承
-
String实现了 Serializable 接口:表示字符串是支持序列化的
实现了Comparable接口:表示String可以比较大小 -
String内部定义了final char[] value用于存储字符串数据
-
String代表不可变的字符序列。简称:不可变性。
二、String的不可变性
1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
2.当对现有字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值
3.当调用String的replace()方法修改指定的字符或字符串时,也需要重新指定内存区域。
5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
6.字符串常量池是不会存储相同内容(使用String类的equals()比较,返回true)的字符串的。String s1="abc";//字面量的定义方式 String s2="abc"; // s1="hello"; System.out.println("s1 == s2:"+(s1 == s2));//比较s1和s2的地址值 System.out.println("s1:"+s1);//hello System.out.println("s2:"+s2);//abc System.out.println("*******"); String s3="abc"; s3+="def"; System.out.println("s3:"+s3);//abcdef System.out.println("s2:"+s2);//abc String s4="abc"; String s5 = s4.replace('a', 'm'); System.out.println("s4:"+s4);//abc System.out.println("s5:"+s5);//mbc
三、String的实例化方式:
方式一:通过字面量定义的方式
方式二:通过new + 构造器的方式面试题:String s= new String(“abc”);方式创建对象。在内存中创建了几个对象?
两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:“abc”//通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中 String s1="javaEE"; String s2="javaEE"; //通过new+构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值 String s3=new String("javaEE"); String s4=new String("javaEE"); System.out.println("s1 == s2:"+s1 == s2);//ture System.out.println("s1 == s3:"+s1 == s3);//false System.out.println("s1 == s4"+s1 == s4);//false System.out.println("s3 == s4"+s3 == s4);//false System.out.println("************************"); Person p1 = new Person("Tom",12); Person p2 = new Person("Tom",12); System.out.println(p1.name.equals(p2.name));//true System.out.println(p1.name == p2.name);//ture p1.name="Jerry"; System.out.println(p2.name);//Tom
结论:
1.常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
2.只要其中有一个是变量,结果就在堆中。
3.如果拼接的结果调用intern()方法,返回值就在常量池中
四、String与其他类型的转换
1.String与基本数据类型、包装类之间的转换。
String -->基本数据类型、包装类:调用包装类的静态方法:parseXxxx(str)
基本数据类型、包装类 -->String: 调用string重载的valueOf(xxx)
String str1 = "123";
// int num =(int) str1;//错误的
int num = Integer.parseInt(str1);//123
String str2 = String.valueOf(num);//"123"
String str3 = num + "";
System.out.println(str1 == str3);//false str3在堆里、str1在常量池中
2.String与char[]之间的转换
String --> char[]调用String的toCharArray()
char[] --> String调用String的构造器
String str1 = "abc123"; //题目:a21cb3
char[] charArray = str1.toCharArray();
for (int i = 0; i < charArray.length; i++) {
System.out.println(charArray[i]);
}
char[] arr= new char[]{'h','e','l','l','o'};
String str2 = new String(arr);
System.out.println(str2);
3.tring 与 byte[]之间的转换
编码: String --> byte[]:调用String的getBytes()
解码: byte[] --> String:调用String的构造器
编码:字符串 -->字节 (看得懂 —>看不懂的二进制数据)
解码:编码的逆过程 ,字节 -->字符串 (看不懂的二进制数据 —>看得懂)
说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码。
@Test
public void test3() throws UnsupportedEncodingException {
String str1 = "abc123中国";
byte[] bytes = str1.getBytes();//使用默认字符集,进行编码(utf-8)
System.out.println(Arrays.toString(bytes));
byte[] gbks = str1.getBytes("gbk");//使用gbk字符集进行编码
System.out.println(Arrays.toString(gbks));
System.out.println("****************************************");
String str2 = new String(bytes);//使用默认的字符集,进行解码(UTF-8)
System.out.println(str2);
String str3 = new String(gbks,"gbk");//出现乱码。原因:编码集和解码集不一致!
System.out.println(str3);
String str4 = new String(gbks,"gbk");//没有出现乱码。原因:编码集和解码集一致!
System.out.println(str4);
}
五、String类型的常用方法
int length(): 返回字符串的长度:return value.length
char charAt(int index): 返回某索引处的字符串:return value[index]
boolean isEmpty(): 判断是否是空字符串: return value.length == 0
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 startWith(String prefix): 测试此字符串是否以指定的前缀开始
boolean startWith(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 formIndex): 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
注: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[] spilt(String regex): 根据给定正则表达式的匹配拆分此字符串。
String[] spilt(String regex,int limit): 根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全放到最后一个元素中。
六、String、StringBuffer与StringBuilder
String、StringBuffer和StringBuilder三者转换
String -->StringBuffer、StringBuilder: 调用StringBuffer、StringBuilder构造器;
StringBuffer、StringBuilder -->String: 调用String构造器;StringBuffer、StringBuilder的toString()
String、StringBuffer和StringBuilder三者的异同?
String:不可变的字符序列;底层使用char[]存储;
StringBuffer:可变的字符序列;线程安全、效率低;底层使用char[]存储;
StringBuilder:可变的字符序列;jdk5.0新增的 线程不安全、效率高;底层使用char[]存储;
源码分析:
String str = new String();//char[] value = new char[0];
String str1 = new String(“abc”);//char[] value = new char[]{‘a’,‘b’,‘c’};
StringBuffer sb1 = new StringBuffer();//value = new char[16];底层创建了一个长度是16的数组
System.out.println(sb1.length());//0
sb1.append(‘a’);//value[0] = ‘a’;
sb1.append(‘b’);//value[1] = ‘b’;
StringBuffer sb2 = new StringBuffer(“abc”);//char[] value = new char[“abc”.length()+16]
//问题1.Stytem.out.println(sb2.length());//3
//问题2.扩容问题:如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组。
默认情况下,扩容为原来容量的2倍 + 2,同时将原有数组的元素复制到新的数组中。
指导意义:开发中建议大家使用StringBuffer(int capacity)或者StringBuilder(int capacity)
StringBuffer的常用方法:(StringBuilder类似)
StringBuffer append(xxx): 提供了很多的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(): 把当前字符串序列逆转
public int indexOf(String str)
public String substring(int start, int end): 返回一个从start开始到end索引结束的左闭右开区间的子字符串
public int length()
public char charAt(int n)
public void setCharAt(int n, char ch)
总结:
增:append(xxx)
删: 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()
对比String、StringBuffer和StringBuilder三者的效率:
从高到低排列:StringBuilder>StringBuffer>String