String(JDK1.8)原始碼閱讀記錄
版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/weixin_40254498/article/details/82464207
String
- 在 Java 中字串屬於物件。
- Java 提供了 String 類來建立和操作字串。
定義
使用了final ,說明該類不能被繼承。同時還實現了:
- java.io.Serializable
- Comparable
- CharSequence
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence { }
屬性
/** The value is used for character storage.
* String就是用char[]實現的。儲存的
*/
private final char value[];
/** Cache the hash code for the string
* hash 值
*/
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability
* Java的序列化機制是通過在執行時判斷類的serialVersionUID來驗證版本一致性的。
*/
private static final long serialVersionUID = -6849794470754667710L;
/**
* Class String is special cased within the Serialization Stream Protocol.
* 類字串在序列化流協議中是特殊的。
* A String instance is written into an ObjectOutputStream according to
* 將字串例項寫入ObjectOutputStream中,根據 a標籤
* <a href="{@docRoot}/../platform/serialization/spec/output.html">
* Object Serialization Specification, Section 6.2, "Stream Elements"</a>
*/
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
構造方法
String 的構造方法大概有十幾種,其中最常用的如下:
/**
* 根據字串建立字串物件
* Initializes a newly created {@code String} object so that it represents
* the same sequence of characters as the argument; in other words, the
* newly created string is a copy of the argument string. Unless an
* explicit copy of {@code original} is needed, use of this constructor is
* unnecessary since Strings are immutable.
*
* @param original
* A {@code String}
*/
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
/**
* 根據byte陣列建立字串物件
* byte[] to String 是根據系統的編碼來的,但是也可以自己指定編碼
* Constructs a new {@code String} by decoding the specified array of bytes
* using the platform`s default charset. The length of the new {@code
* String} is a function of the charset, and hence may not be equal to the
* length of the byte array.
*
* <p> The behavior of this constructor when the given bytes are not valid
* in the default charset is unspecified. The {@link
* java.nio.charset.CharsetDecoder} class should be used when more control
* over the decoding process is required.
*
* @param bytes The bytes to be decoded into characters
* @since JDK1.1
*/
public String(byte bytes[]) {
this(bytes, 0, bytes.length);
}
/**
* 在Java中,String例項中儲存有一個char[]字元陣列,char[]字元陣列是以unicode碼來儲存的,
* String 和 char 為記憶體形式,byte是網路傳輸或儲存的序列化形式。
* 所以在很多傳輸和儲存的過程中需要將byte[]陣列和String進行相互轉化。
* 所以,String提供了一系列過載的構造方法來將一個字元陣列轉化成String,
* 提到byte[]和String之間的相互轉換就不得不關注編碼問題。
* 例如:
* public String(byte bytes[], int offset, int length, Charset charset) {}
* String(byte bytes[], String charsetName)
* String(byte bytes[], int offset, int length, String charsetName)
* and so on
* String(byte[] bytes, Charset charset)是指通過charset來解碼指定的byte陣列,
* 將其解碼成unicode的char[]陣列,夠造成新的String。
*
* 下面這個構造方法可以指定位元組陣列的編碼
* Constructs a new {@code String} by decoding the specified array of
* bytes using the specified {@linkplain java.nio.charset.Charset charset}.
* The length of the new {@code String} is a function of the charset, and
* hence may not be equal to the length of the byte array.
*
* <p> This method always replaces malformed-input and unmappable-character
* sequences with this charset`s default replacement string. The {@link
* java.nio.charset.CharsetDecoder} class should be used when more control
* over the decoding process is required.
*
* @param bytes
* The bytes to be decoded into characters
*
* @param charset
* The {@linkplain java.nio.charset.Charset charset} to be used to
* decode the {@code bytes}
*
* @since 1.6
*/
public String(byte bytes[], Charset charset) {
this(bytes, 0, bytes.length, charset);
}
/**
* 根據char陣列
* Allocates a new {@code String} so that it represents the sequence of
* characters currently contained in the character array argument. The
* contents of the character array are copied; subsequent modification of
* the character array does not affect the newly created string.
*
* @param value
* The initial value of the string
*/
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
/**
* 根據 StringBuffer 建立 String物件
* Allocates a new string that contains the sequence of characters
* currently contained in the string buffer argument. The contents of the
* string buffer are copied; subsequent modification of the string buffer
* does not affect the newly created string.
*
* @param buffer
* A {@code StringBuffer}
*/
public String(StringBuffer buffer) {
synchronized(buffer) {
this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
}
}
/**
* 根據 StringBuilder 建立 String物件
* Allocates a new string that contains the sequence of characters
* currently contained in the string builder argument. The contents of the
* string builder are copied; subsequent modification of the string builder
* does not affect the newly created string.
*
* <p> This constructor is provided to ease migration to {@code
* StringBuilder}. Obtaining a string from a string builder via the {@code
* toString} method is likely to run faster and is generally preferred.
*
* @param builder
* A {@code StringBuilder}
*
* @since 1.5
*/
public String(StringBuilder builder) {
this.value = Arrays.copyOf(builder.getValue(), builder.length());
}
/*
* 這是一個受保護構造方法,因為不能繼承,所以內部使用
* 第二個屬性基本沒有用,只能是true
* 從程式碼中可以看出來是直接引用,而不是新建一個,為了提高效能,節省記憶體等。
* 保護的原因也是為了保證字串不可修改。
* 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;
}
常用的方法
getByte
/**
* 將字串轉成可用的 byte陣列
* 在通訊的比較多,例如 網路中傳輸、8583報文、socket通訊
* 要想不亂碼,就得搞清楚通訊雙方所使用的位元組編碼!!!
* Encodes this {@code String} into a sequence of bytes using the named
* charset, storing the result into a new byte array.
*
* <p> The behavior of this method when this string cannot be encoded in
* the given charset is unspecified. The {@link
* java.nio.charset.CharsetEncoder} class should be used when more control
* over the encoding process is required.
*
* @param charsetName
* The name of a supported {@linkplain java.nio.charset.Charset
* charset}
*
* @return The resultant byte array
*
* @throws UnsupportedEncodingException
* If the named charset is not supported
*
* @since JDK1.1
*/
public byte[] getBytes(String charsetName)
throws UnsupportedEncodingException {
if (charsetName == null) throw new NullPointerException();
return StringCoding.encode(charsetName, value, 0, value.length);
}
/**
* 同上
* Encodes this {@code String} into a sequence of bytes using the given
* {@linkplain java.nio.charset.Charset charset}, storing the result into a
* new byte array.
*
* <p> This method always replaces malformed-input and unmappable-character
* sequences with this charset`s default replacement byte array. The
* {@link java.nio.charset.CharsetEncoder} class should be used when more
* control over the encoding process is required.
*
* @param charset
* The {@linkplain java.nio.charset.Charset} to be used to encode
* the {@code String}
*
* @return The resultant byte array
*
* @since 1.6
*/
public byte[] getBytes(Charset charset) {
if (charset == null) throw new NullPointerException();
return StringCoding.encode(charset, value, 0, value.length);
}
/**
* 將使用系統預設編碼。
* 要注意的,部署的時候容易出錯的地方就是這裡,
* windows 環境和linux環境位元組編碼不一樣.所以建議指定編碼方法
* Encodes this {@code String} into a sequence of bytes using the
* platform`s default charset, storing the result into a new byte array.
*
* <p> The behavior of this method when this string cannot be encoded in
* the default charset is unspecified. The {@link
* java.nio.charset.CharsetEncoder} class should be used when more control
* over the encoding process is required.
*
* @return The resultant byte array
*
* @since JDK1.1
*/
public byte[] getBytes() {
return StringCoding.encode(value, 0, value.length);
}
hashCode
/**
* hash演算法
* hashCode可以保證相同的字串的hash值肯定相同,
* 但是,hash值相同並不一定是value值就相同。
* 所以要保證兩個字串相等還得用上 equals
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
*/
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
equals
/**
*
* 在hashmap中
* 一定要重寫 equals 和 hachcode
* 才能保證是同一個字串
* 正因為String 重寫了我們才能愉快的使用字串作為key
*/
public boolean equals(Object anObject) {
/** 首先判斷是不是自己!*/
if (this == anObject) {
return true;
}
/** 在判斷是不是String型別 */
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;
}
substring
這個方法在JDK1.6(含1.6)以前和JDK1.7之後(含1.7)有了不一樣的變化
JDK1.6 substring
/**
* 仍然建立新的字串但是 舊字串還在 只是新的引用了舊的一部分
* 但舊字串很大的時候,因為新的引用一小部分而無法回收會導致記憶體洩漏
* 一般使用加上一個空的字串來生成新的解決這個問題
* str = str.substring(x, y) + ""
*/
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
public String substring(int beginIndex, int endIndex) {
/** 校驗陣列溢位 */
return new String(offset + beginIndex, endIndex - beginIndex, value);
}
- 記憶體洩露:在電腦科學中,記憶體洩漏指由於疏忽或錯誤造成程式未能釋放已經不再使用的記憶體。 記憶體洩漏並非指記憶體在物理上的消失,而是應用程式分配某段記憶體後,由於設計錯誤,導致在釋放該段記憶體之前就失去了對該段記憶體的控制,從而造成了記憶體的浪費。
JDK1.8 substring
jdk1.7之後直接新建了一個字串 。雖然增加了記憶體,但是解決了記憶體洩漏問題。
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
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);
}
valueOf
/** 呼叫物件自己的toString方法 */
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
public static String valueOf(char data[]) {
return new String(data);
}
public static String valueOf(char data[], int offset, int count) {
return new String(data, offset, count);
}
String + 號過載
String str = "abc";
String str1= str + "def";
/** 反編譯之後 */
String str = "abc";
String str1= (new StringBuilder(String.valueOf(str))).append("def").toString();
spilt
按照字元regex將字串分成limit份。
public String[] split(String regex, int limit) {
/* fastpath if the regex is a
(1)one-char String and this character is not one of the
RegEx`s meta characters ".$|()[{^?*+\", or
(2)two-char String and the first char is the backslash and
the second is not the ascii digit or ascii letter.
*/
char ch = 0;
if (((regex.value.length == 1 &&
".$|()[{^?*+\".indexOf(ch = regex.charAt(0)) == -1) ||
(regex.length() == 2 &&
regex.charAt(0) == `\` &&
(((ch = regex.charAt(1))-`0`)|(`9`-ch)) < 0 &&
((ch-`a`)|(`z`-ch)) < 0 &&
((ch-`A`)|(`Z`-ch)) < 0)) &&
(ch < Character.MIN_HIGH_SURROGATE ||
ch > Character.MAX_LOW_SURROGATE))
{
int off = 0;
int next = 0;
boolean limited = limit > 0;
ArrayList<String> list = new ArrayList<>();
while ((next = indexOf(ch, off)) != -1) {
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
} else { // last one
//assert (list.size() == limit - 1);
list.add(substring(off, value.length));
off = value.length;
break;
}
}
// If no match was found, return this
if (off == 0)
return new String[]{this};
// Add remaining segment
if (!limited || list.size() < limit)
list.add(substring(off, value.length));
// Construct result
int resultSize = list.size();
if (limit == 0) {
while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
resultSize--;
}
}
String[] result = new String[resultSize];
return list.subList(0, resultSize).toArray(result);
}
return Pattern.compile(regex).split(this, limit);
}
按照字元regex將字串分割
/** 直接呼叫 split(String regex, int limit) limit 為 零 */
public String[] split(String regex) {
return split(regex, 0);
}
equalsIgnoreCase
public boolean equalsIgnoreCase(String anotherString) {
return (this == anotherString) ? true
: (anotherString != null)
&& (anotherString.value.length == value.length)
&& regionMatches(true, 0, anotherString, 0, value.length);
}
三目運算子加 && 代替 多個if
replaceFirst、replaceAll、replace
String replaceFirst(String regex, String replacement)
String replaceAll(String regex, String replacement)
String replace(CharSequence target, CharSequence replacement)
- replace的引數是char和CharSequence,即可以支援字元的替換,也支援字串的替換
- replaceAll和replaceFirst的引數是regex,即基於規則表示式的替換,replace只要有符合就替換
- replaceFirst(),只替換第一次出現的字串;
其他方法
String 類中還有很多方法。例如:
- public int length(){}
返回字串長度 - public boolean isEmpty() { }
返回字串是否為空 - public char charAt(int index) {}
返回字串中第(index+1)個字元 - public char[] toCharArray() {}
轉化成字元陣列 - public String trim(){}
去掉兩端空格 - public String toUpperCase(){}
轉化為大寫 - public String toLowerCase(){}
轉化為小寫 - public String concat(String str) {}
拼接字串 - public boolean matches(String regex){}
判斷字串是否匹配給定的regex正規表示式 - public boolean contains(CharSequence s)
判斷字串是否包含字元序列s
相關文章
- JDK原始碼閱讀:String類閱讀筆記JDK原始碼筆記
- JDK1.8 ConcurrentHashMap原始碼閱讀JDKHashMap原始碼
- JDK1.8原始碼閱讀筆記(1)Object類JDK原始碼筆記Object
- RIPS原始碼閱讀記錄(二)原始碼
- JDK原始碼閱讀-String類JDK原始碼
- JDK1.8原始碼分析03之idea搭建原始碼閱讀環境JDK原始碼Idea
- Java原始碼閱讀之TreeMap(紅黑樹) - JDK1.8Java原始碼JDK
- 【原始碼閱讀】AndPermission原始碼閱讀原始碼
- JDK原始碼閱讀:Object類閱讀筆記JDK原始碼Object筆記
- python原始碼閱讀筆記Python原始碼筆記
- CopyOnWriteArrayList原始碼閱讀筆記原始碼筆記
- ArrayList原始碼閱讀筆記原始碼筆記
- LinkedList原始碼閱讀筆記原始碼筆記
- guavacache原始碼閱讀筆記Guava原始碼筆記
- LongAdder原始碼閱讀筆記原始碼筆記
- Koa 原始碼閱讀筆記原始碼筆記
- JDK原始碼閱讀(4):HashMap類閱讀筆記JDK原始碼HashMap筆記
- JDK原始碼閱讀(5):HashTable類閱讀筆記JDK原始碼筆記
- JDK原始碼閱讀(7):ConcurrentHashMap類閱讀筆記JDK原始碼HashMap筆記
- Java原始碼閱讀-String中的private final char value[];Java原始碼
- Express Session 原始碼閱讀筆記ExpressSession原始碼筆記
- Vue2.x 響應式部分原始碼閱讀記錄Vue原始碼
- 【原始碼閱讀】Glide原始碼閱讀之into方法(三)原始碼IDE
- 【原始碼閱讀】Glide原始碼閱讀之with方法(一)原始碼IDE
- JDK原始碼閱讀(3):AbstractStringBuilder、StringBuffer、StringBuilder類閱讀筆記JDK原始碼UI筆記
- 【原始碼閱讀】Glide原始碼閱讀之load方法(二)原始碼IDE
- goroutine排程原始碼閱讀筆記Go原始碼筆記
- 【iOS印象】GLPubSub 原始碼閱讀筆記iOS原始碼筆記
- Flask 原始碼閱讀筆記 開篇Flask原始碼筆記
- Redux 學習筆記 – 原始碼閱讀Redux筆記原始碼
- 【初學】Spring原始碼筆記之零:閱讀原始碼Spring原始碼筆記
- Hive Tutorial 閱讀記錄Hive
- AmplifyImpostors原始碼閱讀原始碼
- stack原始碼閱讀原始碼
- AQS原始碼閱讀AQS原始碼
- delta原始碼閱讀原始碼
- CountDownLatch原始碼閱讀CountDownLatch原始碼
- HashMap 原始碼閱讀HashMap原始碼