在Java编程中, String类型使用特别频繁。但是要发挥String的作用,需要对String源码深入理解,才能写出高质量的代码。
C语言不存在字符串类型,但可用字符数组表示字符串。万变不离其宗,String的底层是基于字符数组,并且封装了操作字符串的一系列方法。所以,String的本质是基于字符数组。
深入理解String,需要重点掌握以下几点:
**1、String是不可变字符串
2、所有对String的修改都会返回新String
3、==和equal的区别**
且看部分关键源码
/**
*这段注释对理解String非常重要,请仔细琢磨
* Strings are constant; their values cannot be changed after they
* are created. String buffers support mutable strings.
* Because String objects are immutable they can be shared. For example:
* <p><blockquote><pre>
* String str = "abc";
* </pre></blockquote><p>
* is equivalent to:
* <p><blockquote><pre>
* char data[] = {'a', 'b', 'c'};
* String str = new String(data);
* </pre></blockquote><p>
* */
//**final修饰String,String不可被继承,保证不可变性**
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/**
这是一个字符数组,String的所有方法都是基于该字符数组
如何保证String字符串不可变
**-用private修饰value,使得value不可被外部访问
-用final修饰value, 不允许value指向另一个地址
-所有String方法不改变value**
以上三个因素保证了String字符串不可变
*/
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
public String() {
this.value = new char[0];
}
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
String不可变的特性,使得String字符串可被共享:
通过共享字符串,相同的字符串,不需额外分配内存空间,减少内存开销,也有利于GC高效运行。
//代码片段
String str = "abc";//会在常量池创建"abc"
String sharedStr = "abc";//常量池已存在"abc",不需要重新分配内存,直接引用常量池
System.out.println(str == sharedStr);//true,引用常量池同一个字符串
所有对String的修改都会返回新String:
由于String字符串是不可变的。所有对String的修改,会给新String分配内存空间,并且将该String拷贝到新String。
//代码片段
String str = "hi,小佳";
String str1 = "my name is ben";
String newStr = str + str1;//为newStr重新分配内存,分别将str和str1拷贝到newStr
System.out.println(str == newStr);//false,字符串内存首地址不相同
==和equals的区别:
以下是==和equals的测试案例,务必研究一番:
/**
*** == 比较两个字符串首地址是否相等**
*/
String str = "str是字符串首地址";//str实际存储的是字符串内存首地址
String sameStr = str;//sameStr、str指向同一个内存地址
String diffStr = "diffStr是字符串首地址,我拥有自己的内存空间";
System.out.println(str == sameStr);//true,字符串内存首地址相同
System.out.println(str == diffStr);//false,字符串内存首地址不相同
/**
*下面是equals源码
***equals:只要两个字符串的内存首地址相等 或者
*字符串内容相等,equals返回true;否则,返回false。**
*
*String重写了equals方法,且看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;
}
//测试案例
String str = "hi,小佳";
String sameStr = "hi,小佳";
String diffStr = new String( "hi,小佳");//只要new一个String,都会给该String分配新的地址空间
System.out.println(str == diffStr);//false,字符串内存首地址不相同
System.out.println(str == sameStr);//true,字符串内存首地址相同
System.out.println(str.equals(diffStr));//true,字符串内容相等
System.out.println(str.equals(sameStr));//true,字符串内存首地址不相同
==和equals的区别总结:
给定两个String对象 str1和str2,如果str1==str2为true,那么str1.equals(str2)必定为true。
总结
String是Java的基础,也是Java中最为常用、最为重要的一个类型,深入理解String,为后续Java高级编程夯实基础!
如果希望进一步理解String,推荐直接看源码,建议重点阅读这几个函数:hashCode(String的哈希算法,值得研究), toString(String重写了这个方法),getBytes(重点了解,此函数设计的编码知识),subString(这个方法比较常用),split。
如果上面这些知识还满足不了你的话,可以继续深入学习StringBuilder,StringBuffer。需要掌握如下两个知识点:
1. String,StringBuilder,StringBuffer区别(理解这三个类的区别,非常重要!)
2. StringBuilder,StringBuffer的应用场景