String類表示字符串,所有類似"abc"形式的字符串(或魔法字符串)都被看作是這個類的實(shí)例。String是不可變的院领,當(dāng)一個字符串在常量池中被創(chuàng)建時(shí),他的值就不會被改變够吩。
不可變類指的是其實(shí)例不能被修改的類比然。每個實(shí)例中包含的所有信息都必須在創(chuàng)建該實(shí)例的時(shí)候就提供,并且在對象的整個生命周期內(nèi)固定不變周循。為了使類不可變强法,要遵循下面五條規(guī)則:
1. 不要提供任何會修改對象狀態(tài)的方法万俗。
2. 保證類不會被擴(kuò)展。 一般的做法是讓這個類稱為 final 的饮怯,防止子類化闰歪,破壞該類的不可變行為。
3. 使所有的域都是 final 的蓖墅。
4. 使所有的域都成為私有的库倘。 防止客戶端獲得訪問被域引用的可變對象的權(quán)限,并防止客戶端直接修改這些對象论矾。
5. 確保對于任何可變性組件的互斥訪問于樟。 如果類具有指向可變對象的域,則必須確保該類的客戶端無法獲得指向這些對象的引用拇囊。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence
所在路徑:\java\lang\String.java
一、成員變量
為了保證String類是一個不可變類靶橱,String類的成員變量多為私有和不可變的寥袭。
/** 存儲String對象的值 */
private final char value[];
/** hashcode */
private int hash;
/** serialVersionUID */
private static final long serialVersionUID = -6849794470754667710L;
/** 序列化時(shí)使用,表明需要序列化的部分 */
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
其中serialPersistentFields在序列化時(shí)使用:
For class that implements Serializable interface there are 2 ways to define what specific fields get streamed during the serialization:
1关霸、By default all non-static, non-transient fields that implement Serializable are preserved.
2传黄、By definning ObjectStreamField [] serialPersistentFields and explicitly declaring the specific fields saved.
The 'advantage' is that it does what it says in the Javadoc: defines which fields are serialized. Without it, all non-transient non-static fields are serialized. Your choice.
二、構(gòu)造器
JDK8的String類一共有16個構(gòu)造器队寇,其中兩個是@Deprecated膘掰,一個是私有構(gòu)造器,剩下的13個是可以調(diào)用的佳遣。
1识埋、無參構(gòu)造器
無參構(gòu)造器直接將""的value賦值給當(dāng)前類的value。""的value是一個空的char[]零渐,其length為0窒舟。調(diào)用使用了無參構(gòu)造器的String對象的isEmpty()方法會得到true,調(diào)用length()方法會得到0诵盼,判斷其==null會得到false惠豺。
public String() {
this.value = "".value;
}
2、入?yún)镾tring對象
入?yún)镾tring對象時(shí)风宁,構(gòu)造器會對其進(jìn)行直接取值洁墙。
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
3、入?yún)閏har[]
入?yún)樽址當(dāng)?shù)組時(shí)戒财,構(gòu)造器調(diào)用的是Arrays.copyOf()方法热监。
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
其中Arrays.copyOf()方法是為了將入?yún)⒌淖址蛄猩羁截惖絫his.valuie中,他的源碼為:
public static char[] copyOf(char[] original, int newLength) {
char[] copy = new char[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
其中System.arraycopy()方法的源碼為:
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
String和char[]的相互轉(zhuǎn)換:
https://www.cnblogs.com/rrttp/p/7922202.html
4固翰、入?yún)閏har[]狼纬,偏移量和有效長度
這個方法支持直接傳入想要生成的String的母串羹呵,通過偏移量和有效長度找出需要賦值給this.value的部分,然后調(diào)用Arrays.copyOfRange()方法進(jìn)行深拷貝疗琉。
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);
}
5冈欢、其他
當(dāng)需要將一個Unicode編碼序列轉(zhuǎn)換為String時(shí),可以使用以下構(gòu)造器:
public String(int[] codePoints, int offset, int count)
參考:https://blog.csdn.net/qq_39477410/article/details/82469104
當(dāng)需要將一個bytes[]轉(zhuǎn)換為String時(shí)盈简,可以使用以下構(gòu)造器:
// 可以傳入JDK支持的字符集名稱
public String(byte bytes[], int offset, int length, String charsetName)
throws UnsupportedEncodingException
// 也可以傳入自定義的解碼字符集
public String(byte bytes[], int offset, int length, Charset charset)
此外凑耻,還有一些將上述構(gòu)造器進(jìn)一步封裝的構(gòu)造器,其本質(zhì)都是簡化入?yún)⒛汀A硗庀愫疲琒tring類的構(gòu)造器同樣支持傳入StringBuffer和StringBuilder。如果傳入的是StringBuffer臼勉,構(gòu)造器會為其加鎖邻吭。如果傳入的是StringBuilder則不會加鎖。
public String(StringBuffer buffer) {
synchronized(buffer) {
this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
}
}
public String(StringBuilder builder) {
this.value = Arrays.copyOf(builder.getValue(), builder.length());
}
事實(shí)上宴霸,StringBuffer和StringBuilder的toString()方法調(diào)用的也是String類的構(gòu)造器囱晴,他們最終的底層實(shí)現(xiàn)都是Arrays.copyOf()。
// StringBuffer的toString()方法
@Override
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
// StringBuilder的toString()方法
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
最后瓢谢,String類還提供了一個保護(hù)類型的構(gòu)造方法畸写。該方法相比入?yún)閏har[]的構(gòu)造器多了一個share參數(shù),這個參數(shù)并沒有實(shí)際作用氓扛,只是用來和其他構(gòu)造器進(jìn)行區(qū)分枯芬。當(dāng)String類內(nèi)部調(diào)用該構(gòu)造器時(shí):
- 直接賦值而不是使用Arrays.copyOf()方法可以獲得更高的效率;
- 同時(shí)共享字符串?dāng)?shù)組的方式也可以節(jié)省內(nèi)存采郎。
該構(gòu)造器不能對外暴露的原因是需要保持String類的不可變性千所。
/*
* Package private constructor which shares value array for speed.
* this constructor is always expected to be called with share==true.
* a separate constructor is needed because we already have a public
* String(char[]) constructor that makes a copy of the given char[].
*/
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}