目录
String
1.概念
java.lang.String表示字符串,属于引用数据类型,是final类型的,即不可变的。并且不能继承、不能修改这个类。源码如下:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { //... }
2.特性
1.String不适合于频繁修改。一般为了提高效率节省空间,使用StringBuff. 2.String在内存中采用Unicode编码方式,任何一个字符对应两个字节的定长编码。 3.使用
方式一:String s = "abc"; 方式二:String s = new String("abs");
4.字面量
字面量就是常量
5.String常量池
出于性能考虑,为了避免在一个系统中产生大量的String对象,JVM会将字符串字面量对象缓存在常量池中(常量池可以理解为String[]数组)。
所以,创建一个字符串时,JVM首先会在池中检查是否有值相同的字符串对象,若存在则返回该对象的引用;如果没有则新建字符串对象,返回对象的引用,并且将新创建的对象放入池中。但是,通过new方法创建的String对象是不检查字符串常量池的,而是直接在堆中创建新对象,也不会把对象放入池中。上述原则只适用于直接给String对象引用赋值的情况。
如下所示:
public class Test{ public static final HELLO = "hello"; public static void main(String[] args){ String s1 = "123hello"; String s2 = "123hello"; String s3 = "123" + "hello"; String s4 = 1 + 2 + 3 + "hello"; String s5 = "1" + 2 + 3 + "hello"; String s6 = '1' + '2' + '3' + "hello"; //通过new方式创建String对象不检查常量池 String s7 = new String("123hello"); String a = "123"; String b = "hello"; String s8 = a + b; String s9 = "123" + b; String s9 = "123" + HELLO; System.out.println(s2 == s1); //返回true System.out.println(s3 == s1); //返回true,在编译时s3变为123hello System.out.println(s4 == s1); //返回false,s4为6hello System.out.println(s5 == s1); //返回true,s5为123hello System.out.println(s6 == s1); //返回false System.out.println(s7 == s1); //返回false,重新创建一个String对象 System.out.println(s8 == s1); //返回false,a和b属于变量,不会检查常量池 System.out.println(s9 == s1); //返回false,b属于变量,不会检查常量池 System.out.println(s10 == s1); //返回true,HELLO属于常量 } }
6.常用API
- public boolean equals(Object anObject)
String的equals方法继承自Object,并且重写了该方法,比较两个字符串的内容(字符串序列)是否相同,相同返回true;否则返回false。
注意:==比较的是地址,equals比较的是内容。
源码如下:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; } }
- public boolean equalsIgnoreCase(String anotherString)
equlasIgnoreCase跟equals比较的都是字符串的内容,只是equlasIgnoreCase会忽略字符串的大小写。源码如下所示:
public boolean equalsIgnoreCase(String anotherString) { return (this == anotherString) ? true : (anotherString != null) && (anotherString.value.length == value.length) && regionMatches(true, 0, anotherString, 0, value.length); }
- int indexOf(...)
返回检索的索引下标。
- String trim()
返回去掉首尾空白字符后的字符串。
- 截取字符串
String substring(int formIndex) 返回从给定索引位置formIndex开始到字符串结尾的子字符串 String substring(int formIndex, int endIndex) 返回从formIndex到endIndex-1的子字符串
- char[] toCharArray()
返回字符串内部维护的字符数组。
- 分割字符串
1.public String[] split(String regex)
将当前字符串按照给的的正则表达式格式进行分割,返回一个分割后的String数组 2.public String[] split(String regex, int limit) 注意事项:
注意点1: String str = ",1,2,"; System.out.println(Arrays.toString(str.split(",")); 输出结果为: [,1,2] 注意点2: String str = ".1.2.3."; System.out.println(Arrays.toString(str.split("\\.")); //要使用转义字符\ 输出结果为: [,1,2,3] 注意点3:切割空白字符 String str = " 1 2 3 "; System.out.println(Arrays.toString(str.split("\\s+")); 输出结果为: [,1,2,3]
- 替换字符串
1.public String replaceAll(String regex, String replacement) 将当前字符串按照给的的正则表达式和给定的替换内容
进行替换,返回替换后的新字符串。
- 还有很多常用API......
StringBuffer与StringBuilder
1.相同
1.和String不同的是,StringBuffer和StringBuilder封装可变的字符串。 2.StringBuffer和StringBuilder就是为了解决大量拼接字符串时产生很多中间对象问题的一个类。提供append和add,可以将字符串添加到已有字符串序列的末尾或指定位置。即对象创建后可由通过调用方法改变其封装的字符串序列。 3.StringBuffer和StringBuilder二者都继承了AbstractStringBuilder,底层都是利用可修改的char数组(JDK9以后是byte数组)。
所以如果有大量的字符串拼接,如果能预知大小的话最好在new StringBuffer 或者StringBuilder 的时候设置好capacity,避免多次扩容的开销。扩容要抛弃原有数组,还要进行数组拷贝创建新的数组。
2.不同
- StringBuffer是线程安全的,增加了开销;StringBuilder是JDK1.5发布的,是线程不安全的,减少了开销。
StringBuffer
1.本质
StringBuffer本质是一个线程安全的可修改的字符序列,把所有修改数据的方法都加上了synchronized。但是保证了线程安全是需要付出代价的。
2.常用API
跟StringBuilder一样
StringBuilder
1.使用
//构造方法StringBuilder()将创建不含任何字符序列的StringBuilder对象(为空字符串"") StringBuilder sb = new StringBuilder(); //构造方法StringBuilder(String str)将创建含str字符序列的StringBuilder对象 StringBuilder sb = new StringBuilder("字符串”);
2.常用API
- append(追加)
- delete(移除)
- insert(插入)
- reserve(反转)
- replace(替换)
public StringBuilder replace(int start,int end,String str) 使用给定
String
中的字符替换此序列的子字符串中的字符。该子字符串从指定的
start
处开始,一直到索引end - 1
处的字符
使用总结
- 在字符串不经常发生变化的业务场景优先使用String。如常量的声明,少量字符串操作(拼接、删除等)
- 在单线程情况下,如果有大量字符串操作情况,应该使用StringBuilder。不能使用String"+"来拼接而是使用,避免产生大量无用的中间对象,耗费空间且执行效率低下(新建对象、回收对象花费大量时间)。如JSON的封装等。
- 在多线程情况下,如果有大量字符串操作情况,应该使用StringBuffer。如Http参数解析和封装。
参考:https://baijiahao.baidu.com/s?id=1629804867201303563&wfr=spider&for=pc