String详解:
(1)String不属于基本数据类型,Stirng是一个对象
(2)String类被final修饰,不可以被
(3)String可以通过“+“连接
(4)String类的本质是char[]
(5)String运行时维护常量池
类的定义及主要属性
(1)类的定义:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
(2)主要属性(GDK1.6):
private final char value[]; //String本质就是Char数组
private final int offset; //偏移位
private final int count; //就是Sting的length
private int hash; //hash码
final简析
简单的理解:
若变量是基本类型则值不变
若变量是引用类型则引用不变
String内部变量是被Final修饰的,对String的改变不能将原来的String改变,只能重新返回一个新的String。这是String与其他普通对象的重要区别。
通过源码理解"对String的改变不能将原来的String改变,只能重新返回一个新的String"这句话。
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
public static char[] copyOfRange(char[] original, int from, int to) {
int newLength = to - from;
if (newLength < 0)
throw new IllegalArgumentException(from + " > " + to);
char[] copy = new char[newLength];//创建新的数组对象
System.arraycopy(original, from, copy, 0,
Math.min(original.length - from, newLength));
return copy;
}
replace方法我们会误以为会发生值的改变,如下
String str = “123”, str = str.replace('1','a'), 我们会误认为a的值发生改变,查看源码发现其实创建了一个新对象,然后让str指向这个对象。
//源码
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);//创建新的对象
}
}
return this;
}
字符串的创建
(1)new创建 String str = new String(“123“);
此方式一定会在堆区创建一个新对象,使用String类的intern()方法可以将其放入常量池。
(ps:java不要求常量一定在编译期才能产生)
(2)直接指定 String str = “123”;
对象创建时先查看常量池,常量池中存在就不创建,不存在时创建新对象并且放入常量池。
(3)使用“+” String str = “12” + “3”;
使用直接指定或者使用纯字符串来创建时,先检查常量池。如果存在则不创建,不存在时创建新对象并且放入常量池。
(4) String str2 = "12";
String str7 = str2 + "1";
使用包含变量的表达式来创建时不检查常量池。
字符串的创建例子
public class StringTest {
public static void main(String[] args) {
//new创建
String str1 = new String("123");
//直接指定
String str2 = "123";
System.out.println(str1 == str2);//false
//使用 "+"
String str3 = "12" + "3";
System.out.println(str2 == str3);//true
//使用包含变量的表达式来创建
String str4 = new String("12");
String str5 = str4 + "3";
System.out.println(str5 == str2);//false
//使用包含变量的表达式来创建
String str6 = "12";
String str7 = "3";
String str8 = str6 + str7;
System.out.println(str8 == str2);//false
}
}
改变Stirng对象
String对象真的是不可变的吗?其实我们可以使用反射机制改变,例子如下:
public class StringReflection {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
String str = "123";
System.out.println(str); //123
Field valueFiled = String.class.getDeclaredField("value");
//访问属性设置
valueFiled.setAccessible(true);
char[] oldValue = (char[]) valueFiled.get(str);
oldValue[0] = 'A';
System.out.println(str); //A123
}
}