Java基础(四) | 形影不离的String字符串
2017-06-23 本文已影响227人
采风JS
字符串,一个深受折磨的朋友。它并不是基本数据类型,而是一种对象。关于此对象,常涉及到比较、访问、修改操作,是程序员编码的基本功。今天,将String进行深入剖析,做一个合格的蓝颜知己。
1. " "、null和new String()的区别
String s1 = null;
// 未分配内存,未创建引用,未初始化
String s2 = " ";
String s3 = new String();
// 完成初始化,分配内存,创建引用,但其值为空
2. 字符串池
创建字符串对象时,在字符串池中寻找具有相同字面值的对象,如果存在,则返回该对象的引用;如果不存在,则创建对象置于字符串池中,并且返回新创建对象的引用;
字符串池的存在,减少内存开销,所以推荐使用非new的方式,使用String s = "bat"的方式;
3. String、StringBuffer和StringBuilder
-
三者区别
String为不可变的字符串常量,而StringBuffer和StringBuilder为可变的字符串变量;
String和StringBuffer为线程安全的,而StringBuilder为线程不安全的;
针对String的修改操作会产生新的对象,而后两者只是在原有对象上改变,并不产生新的对象; -
应用场景
字符串常量和少量字符串操作时,使用String类;
在频繁字符串修改(替换、拼接和添加)时,比如Http参数解析、封装等,如果为多线程操作,使用StringBuffer,否则使用StringBuilder;
4. String真是不可变对象吗?
可以优先考虑一下这篇博客:Java中的String为什么是可变的?
// String类的源码,jdk1.8
private final char value[]; // String类可以看作是对不可变数组的封装
private int hash;
// 基于反射改变String
public static void main(String[] args) throws Exception{
String name = "Xi Dian";
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
char[] c = (char[]) value.get(name);
c[2] = '_';
System.out.println(name); // 打印结果为: Xi_Dian
}
5. 深入理解拼接操作
- "+"操作符
// 编译器对"+"操作符进行优化,下面两者等效
str += "b";
str = new StringBuilder().append("b").toString();
- concat()方法
// jdk1.8源码 concat方法
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
// 此处的len为原字符串的长度
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
// str将从0到自身length长度拷贝到buf中从len开始之后的位置
str.getChars(buf, len);
// 新建字符串
return new String(buf, true);
}
void getChars(char dst[], int dstBegin) {
System.arraycopy(value, 0, dst, dstBegin, value.length);
}
- append()方法
// jdk1.8的源码 append()方法
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
// 从value的count索引开始,逐个添加str字符数组
str.getChars(0, len, value, count);
count += len;
// 并不产生新的对象
return this;
}