字符串替换处理
使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:
代码示例1:replaceAll方法
String str = "helloworld" ; //结果为he__owor_d System.out.println(str.replaceAll("l", "_"));
代码示例2:replaceFirst方法
String str = "helloworld" ; //结果为he_loworld System.out.println(str.replaceFirst("l", "_"));
代码示例3::replace方法
String str = "helloworld" ; //结果为he__owor_d System.out.println(str.replace("l", "_"));
可以发现replace方法与replaceAll方法的效果一样
来看下replace方法的源码吧:
可以看到replace方法的底层代码中的参数是CharSequence类型,但是我们自己传参的时候是string类型,这是为什么呢?
答:是因为发生了向上转型,String类实现了CharSequence这个接口,如下图所示:
注意事项: 由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串
字符串拆分(用的非常多,需要多注意)
可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。
可用方法如下:
代码示例1:split(String regex)方法
split方法返回的是一个String类型的数组,以下是多次拆分的代码,以后会经常出现
String str = "username=zhangsan&password=123"; //以“&”这个符号进行切割,切割一次后为username=zhangsan password=123 String[] strings = str.split("&"); for (int i = 0; i < strings.length; i++) { //继续对第一次切割后的字符串进行切割 String[] strings1 = strings[i].split("="); for (int j = 0; j < strings1.length; j++) { /*最终结果为: username zhangsan password 123 */ System.out.println(strings1[j]); } }
还有我们会在leetcode刷题的时候经常遇见的使用空格来进行分割:
public class TestDemo5 { public static void main(String[] args) { //注意此处bcd与def之间有两个空格 String str = "abc bcd def"; String[] str1 = str.split(" "); for (String s : str1) { System.out.println(s); } } } //输出结果为 abc bcd def
代码示例2:split(String regex,int limit)方法
limit=1说明只分了一组
String str = "username=zhangsan&password=123"; String[] strings = str.split("&",1); for (int i = 0; i < strings.length; i++) { //输出结果为username=zhangsan&password=123 System.out.println(strings[i]); }
limit=2说明分为两组
String str = "username=zhangsan&password=123"; String[] strings = str.split("&",2); for (int i = 0; i < strings.length; i++) { /*输出结果为: username=zhangsan password=123 */ System.out.println(strings[i]); }
拆分是特别常用的操作. 一定要重点掌握. 另外有些特殊字符作为分割符可能无法正确切分, 需要加上转义
代码示例3:特殊情况
情况1:拆分ip地址这类(单个分隔符)
String str = "192.168.1.1" ; String[] result = str.split("\\.") ; for(String s: result) { /*输出结果为 192 168 1 1 */ System.out.println(s); }
像ip地址这种拆分的时候,如果是拿点号(.)进行拆分的话,需要进行转义,第一次转义是转义点号,第二次转义是保留转义符号的作用,意思就是让第一个\作为转义符号来使用
情况2:多个分隔符的拆分(使用连字符“|”)
String str = "java-split#bit"; //用|作为连字符,将-和#这两个分隔符进行拆分 String[] strings = str.split("-|#"); for (int i = 0; i < strings.length; i++) { /*输出结果为: java split bit */ System.out.println(strings[i]); }
注意事项:
字符"|“,”*“,”+“都得加上转义字符,前面加上”\"
而如果是"“,那么就得写成”\\".
如果一个字符串中有多个分隔符,可以用"|"作为连字符.
字符串截取
从一个完整的字符串之中截取出部分内容。可用方法如下:
代码示例1:substring(int beginIndex)方法
String str = "abcdefg"; String str1= str.substring(3); //输出结果为:defg System.out.println(str1);
注意事项:
索引从0开始,3就是索引为3所对应的那个数字,也就是d
代码示例2:substring(int beginIndex,int endIndex)
String str = "abcdefg"; String str1= str.substring(0,5); //输出结果为:abcde System.out.println(str1);
从0下标开始截取,截取到4号下标,不包含5号下标所对应的字符
注意事项:
注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标
1
其他操作方法
trim方法
trim 会去掉字符串开头和结尾的空白字符(空格, 换行, 制表符等).
public class string { public static void main(String[] args) { String str = " abc de fg "; //输出结果为: abc de fg System.out.println(str); String str1=str.trim(); //输出结果为:abc de fg System.out.println(str1); } }
toUpperCase方法
public class string { public static void main(String[] args) { String str = "abc"; String str1=str.toUpperCase(); //输出结果为:ABC System.out.println(str1); } }
toLowerCase方法
public class string { public static void main(String[] args) { String str = "ABabc"; String str1=str.toLowerCase(); //输出结果为:ababc System.out.println(str1); } }
注意事项:toUpperCase方法和toLowerCase方法这两个方法只转换字母,不转换中文字符。
intern方法(前面已经讲过)
concat方法(不经常用,不做过多赘述)
length方法
public class string { public static void main(String[] args) { String str = "abc"; int length=str.length(); //输出结果为:3 System.out.println(length); } }
注意事项:数组长度使用数组名称.length属性,而String中使用的是length()方法
isEmpty方法
public class string { public static void main(String[] args) { //定义一个空字符串 String str = ""; boolean boolean1=str.isEmpty(); //输出结果为:true System.out.println(boolean1); } }
注意有两种方式可以表示空字符串
第一种方式:String str=“”,这种方式代表指向的字符串对象什么都没有.
第二种方式:String str=null,这种方式代表不指向任何对象
join方法
StringBuffer 和 StringBuilder
首先给出其官方网址:
StringBuffer 类:点我进入官网
StringBuilder 类:点我进入官网
首先来回顾下String类的特点:
任何的字符串常量都是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的是其引用的指向而已。
通常来讲String的操作比较简单,但是由于String的不可更改特性,为了方便字符串的修改,提供StringBuffer和StringBuilder类。
StringBuffer 和 StringBuilder 大部分功能是相同的,我们主要介绍 StringBuffer
在String中使用"+"来进行字符串连接,但是这个操作在StringBuffer类中需要更改为append()方法
使用了append方法进行拼接后,新产生的字符串在字符串常量池就不再生成内存了,就直接在原内存上的字符串进行拼接
代码示例
public class string { public static void main(String[] args) { //append方法的字符串拼接是在原字符串基础上进行拼接的,并不是生成新的字符串 StringBuffer stringBuffer=new StringBuffer("abcd"); //输出结果为abcdefg System.out.println(stringBuffer.append("efg")); } }
为什么append方法会在原字符串上进行拼接呢?
来看append方法的源码:
最后返回的是当前对象的引用(return this),所以就是在原字符串上进行拼接.
append方法可以传的参数类型很多:例如char[],char ,boolean,int,long,float,double,StringBuffer,CharSequence
String与StringBuffer(StringBuilder)的转换
String和StringBuffer(StringBuilder)类不能直接转换。如果要想互相转换,可以采用如下原则:
String变为StringBuffer(StringBuilder):利用StringBuffer(StringBuilder)的构造方法或append()方法 (常用)
StringBuffer(StringBuilder)变为String:调用toString()方法。(常用)
总结
String与StringBuffer,StringBuilder的区别(面试题)
StringBuffer,StringBuilder包含了一些String没有的方法 比如reverse方法
StringBuffer,StringBuilder是可变的,String是不可变的。String的每次拼接,都会产生新的对象。
StringBuffer,StringBuilder每次的拼接都返回的是this,说明是在原字符串上进行拼接的.
StringBuffer与StringBuilder区别(面试题)
先来看StringBuffer,StringBuilder的append方法:
StringBuffer类中的append方法是被synchronized修饰的,
这个关键字可以保证线程的安全.
总结:
StringBuilder和String 出现在单线程情况下
StringBuffer因为有synchronized关键字,所以一般出现多线程情况下。
一般来说非多线程的情况下最好使用StringBuilder,原因是 synchronized关键字涉及到锁的问题,每次的开锁关锁都要消耗资源
StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
String与StringBuilder区别(面试题)
既然都运用于单线程的情况下,那么这两者到底有什么区别呢?
1:String的拼接”+“会被优化 优化为StringBuilder中的append方法,来看分析:
我们将下面这段代码进行编译:
public class string { public static void main(String[] args) { String str="abc"; str=str+"de"; System.out.println(str); } }
编译后得到的如下图所示:
可以看到底部进行了优化,那么对于上述代码来说其实底层在运行的时候的代码如下所示:(代码的执行方式跟图中是一样的)
public class string { public static void main(String[] args) { String str="abc"; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(str); stringBuilder.append("hello"); String str1 = stringBuilder.toString(); System.out.println(str1); } }
所以说对于String类的”+“的拼接,底层虽然是StringBuilder类的append方法的优化,但是其仍然会产生大量的临时空间
再来看之前遗留的一个问题:
public static void main(String[] args) { String str = "abc"; for(int i = 0;i < 10;i++) { str += i; } System.out.println(str); }
上述代码之前我们说因为由于”+“号的拼接,导致会产生大量的临时变量,此时我们来使用StringBuilder的append方法来进行优化:
public class string { public static void main(String[] args) { String str = "abc"; //在循环外定义StringBuilder对象 StringBuilder sb = new StringBuilder(); sb.append(str); for (int i = 0; i < 10; i++) { //循环内部使用append方法 str = sb.append(i).toString(); } System.out.println(str); } }
2:在循环当中 不可以使用String直接进行拼接 这样会产生大量的临时对象
包括优化之后的StringBuilder对象。所以每次定义StringBuilder对象的时候在循环外进行定义,然后在循环内部使用append方法.
小结
字符串操作是我们以后工作中非常常用的操作. 使用起来都非常简单方便, 一定要使用熟练. 指的注意的点:
1.字符串的比较, ==, equals, compareTo 之间的区别.
2.了解字符串常量池, 体会 “池” 的思想.
3.理解字符串不可变
4.split 的应用场景
5.StringBuffer 和 StringBuilder 的功能.
String练习题
练习题1
下面代码将输出什么内容:()
A.true
B.false
C.1
D.编译错误
答:B
原因是toLowerCase方法实际上返回值是一个新的字符串,我们来看源码:
再点toLowerCase:
可以看到返回的是new String这样的字符串,所以它的地址是对象中value数组的地址,而"admin"是存储在字符串常量池的,所以两者地址肯定不同.
练习题2
指出下列程序运行的结果()
A.good and abc
B.good and gbc
C.test ok and abc
D.test ok and gbc
答案:B