- /*
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- package java.lang;
- import java.io.ObjectStreamField;
- import java.io.UnsupportedEncodingException;
- import java.nio.charset.Charset;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Comparator;
- import java.util.Formatter;
- import java.util.Locale;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import java.util.regex.PatternSyntaxException;
- /**
- * The <code>String</code> class represents character strings. All
- * string literals in Java programs, such as <code>"abc"</code>, are
- * implemented as instances of this class.
- * <p>
- * 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>
- * Here are some more examples of how strings can be used:
- * <p><blockquote><pre>
- * System.out.println("abc");
- * String cde = "cde";
- * System.out.println("abc" + cde);
- * String c = "abc".substring(2,3);
- * String d = cde.substring(1, 2);
- * </pre></blockquote>
- * <p>
- * The class <code>String</code> includes methods for examining
- * individual characters of the sequence, for comparing strings, for
- * searching strings, for extracting substrings, and for creating a
- * copy of a string with all characters translated to uppercase or to
- * lowercase. Case mapping is based on the Unicode Standard version
- * specified by the {@link java.lang.Character Character} class.
- * <p>
- * The Java language provides special support for the string
- * concatenation operator ( + ), and for conversion of
- * other objects to strings. String concatenation is implemented
- * through the <code>StringBuilder</code>(or <code>StringBuffer</code>)
- * class and its <code>append</code> method.
- * String conversions are implemented through the method
- * <code>toString</code>, defined by <code>Object</code> and
- * inherited by all classes in Java. For additional information on
- * string concatenation and conversion, see Gosling, Joy, and Steele,
- * <i>The Java Language Specification</i>.
- *
- * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
- * or method in this class will cause a {@link NullPointerException} to be
- * thrown.
- *
- * <p>A <code>String</code> represents a string in the UTF-16 format
- * in which <em>supplementary characters</em> are represented by <em>surrogate
- * pairs</em> (see the section <a href="Character.html#unicode">Unicode
- * Character Representations</a> in the <code>Character</code> class for
- * more information).
- * Index values refer to <code>char</code> code units, so a supplementary
- * character uses two positions in a <code>String</code>.
- * <p>The <code>String</code> class provides methods for dealing with
- * Unicode code points (i.e., characters), in addition to those for
- * dealing with Unicode code units (i.e., <code>char</code> values).
- *
- * @author Lee Boynton
- * @author Arthur van Hoff
- * @author Martin Buchholz
- * @author Ulf Zibis
- * @see java.lang.Object#toString()
- * @see java.lang.StringBuffer
- * @see java.lang.StringBuilder
- * @see java.nio.charset.Charset
- * @since JDK1.0
- */
- /**
- * String類表示一類字符串,Java程序中的字符串都是當前類的實例,並且都是不可變的常量,
- * 它們一旦被創建就不能再被修改。字符串緩衝區支持可變的字符串,
- *
- */
- public final class String
- implements java.io.Serializable, Comparable<String>, CharSequence {
- /** 用於存儲當前字符串包含的字符 */
- private final char value[];
- /** 用於緩存當前字符串的HashCod值,默認值爲零**/
- private int hash;
- private static final long serialVersionUID = -6849794470754667710L;
- /**
- * 這個類主要用來提取序列化過程中某個對象內的字段【成員屬性】元數據信息,
- * 包括字段的類型、類型代碼、簽名等
- */
- private static final ObjectStreamField[] serialPersistentFields =
- new ObjectStreamField[0];
- /**
- * 初始化創建一個新的String對象用來表示一個空字符串。
- * 注意:完全沒必要使用此構造器來創建一個String對象,因爲String自身已經被設計爲不可變
- */
- public String() {
- this.value = new char[0];
- }
- /**
- * 通過傳入一個字符串參數來構建一個空的String對象,換句話說,新創建的字符串對象是
- * 傳入的字符串參數的一個副本。除非你確實需要顯式的複製一個字符串對象,否則你完全
- * 沒必要使用此構造器來創建一個String對象,因爲String自身已經被設計爲不可變
- * @param original 原始的字符串對象
- */
- public String(String original) {
- this.value = original.value;
- this.hash = original.hash;
- }
- /**
- * 通過傳入的一個字符數組來構建一個空的String對象,新創建的String對象是傳入的字符數組的
- * 一個副本,後續你對該字符數組對象的修改不會影響到當前新創建的String對象
- * @param value 字符數組
- */
- public String(char value[]) {
- this.value = Arrays.copyOf(value, value.length);
- }
- /**
- * 通過傳入的一個字符數組並根據指定的offset和count參數來截取得到一個子字符數組,
- * 然後根據子字符數組來構建一個新的字符串對象,新創建的字符串對象是子字符數組內容的
- * 一個副本,後續你對該子字符數組內容的修改不會影響到當前新創建的字符串對象。其中offset
- * 參數表示截取子字符數組時在第一個參數即原字符數組中的起始偏移量,count表示子字符數組的長度。
- * @param value 原字符數組
- * @param offset 截取子字符數組時在原字符數組中的起始偏移量
- * @param count 子字符數組的長度
- *
- * @throws IndexOutOfBoundsException 如果offset或count參數越界了,那麼會拋出此異常
- */
- public String(char value[], int offset, int count) {
- if (offset < 0) {
- throw new StringIndexOutOfBoundsException(offset);
- }
- if (count < 0) {
- throw new StringIndexOutOfBoundsException(count);
- }
- // 如果offset + count > value.length,則會拋出字符串越界異常
- if (offset > value.length - count) {
- throw new StringIndexOutOfBoundsException(offset + count);
- }
- this.value = Arrays.copyOfRange(value, offset, offset+count);
- }
- /**
- * 通過傳入的一個代碼點數組並根據指定的offset和count參數來截取得到一個子字符數組,
- * 然後根據子字符數組來構建一個新的字符串對象,新創建的字符串對象是子字符數組內容的
- * 一個副本,後續你對該代碼點數組內容的修改不會影響到當前新創建的字符串對象。其中offset
- * 參數表示在原代碼點數組中截取的起始偏移量,count表示在原代碼點數組中截取的元素長度。
- * 代碼點最終會被轉換成字符
- * @param codePoints 原代碼點數組
- * @param offset 在原代碼點數組中截取的起始偏移量
- * @param count 在原代碼點數組中截取的元素長度
- *
- * @throws IndexOutOfBoundsException 如果offset或count參數越界了,那麼會拋出此異常
- * @since 1.5
- */
- public String(int[] codePoints, int offset, int count) {
- if (offset < 0) {
- throw new StringIndexOutOfBoundsException(offset);
- }
- if (count < 0) {
- throw new StringIndexOutOfBoundsException(count);
- }
- // 如果offset + count > value.length,則會拋出字符串越界異常
- if (offset > codePoints.length - count) {
- throw new StringIndexOutOfBoundsException(offset + count);
- }
- final int end = offset + count;
- // 階段1:計算char[]的精確大小
- int n = count;
- for (int i = offset; i < end; i++) {
- int c = codePoints[i];
- //判斷一個代碼點是否在基本多語言面(Basic Multilingual Plane,BMP)內
- if (Character.isBmpCodePoint(c)) {
- continue;
- }
- //判斷是否爲一個合法的代碼點
- else if (Character.isValidCodePoint(c)) {
- n++;
- }
- else {
- throw new IllegalArgumentException(Integer.toString(c));
- }
- }
- // 階段2:收集代碼點、轉換成字符char,並裝入char[]
- final char[] v = new char[n];
- for (int i = offset, j = 0; i < end; i++, j++) {
- int c = codePoints[i];
- //判斷一個代碼點是否在基本多語言面(Basic Multilingual Plane,BMP)內
- if (Character.isBmpCodePoint(c)) {
- // 將代碼點轉換成一個字符,BMP Code Point代碼點是65535是2的16次方,
- // 剛好是兩個字節(即一個字)的大小。在超出兩個字節後只能算是有效的代碼點,
- // 並非是BMP Code Point代碼點。從代碼中也可看出,BmpCodePoint代碼點的整數是
- // 可以直接強轉成char類型的。在java中char類型剛好佔2個字節,在2個字節以內的整數
- // 都可以直接強轉換成char類型
- v[j] = (char) c;
- }
- else {
- /**
- * Surrogate這個概念,不是來自Java語言,而是來自Unicode編碼方式之一:UTF-16。
- * 具體請見: <a href="https://en.wikipedia.org/wiki/UTF-16">UTF-16</a>
- * 簡而言之,Java語言內部的字符信息是使用UTF-16編碼。因爲char這個類型是16-bit的,
- * 它可以有65536種取值,即65536個編號,每個編號可以代表1種字符。但是Unicode
- * 包含的字符已經遠遠超過65536個。那編號大於65536的,還要用16-bit編碼,該怎麼辦?
- * 於是Unicode標準制定組想出的辦法就是,從這65536個編號裏,拿出2048個,規定它們是「Surrogates」,
- * 讓它們兩個爲一組,來代表編號大於65536的那些字符。更具體地,
- * 編號從U+D800至U+DBFF的規定爲「High Surrogates」,共1024個。
- * 編號爲 U+DC00至U+DFFF的規定爲「Low Surrogates」,也是1024個,
- * 它們兩兩組合出現,就又可以多表示1048576種字符。
- */
- Character.toSurrogates(c, v, j++);
- }
- }
- this.value = v;
- }
- /**
- * 通過傳入一個ASCII碼的字節數組來構建一個新的字符串對象
- * 注意:此方法不能正確的將字節數組轉成字符,自JDK1.1版本起,實現此功能更佳的方式是
- * 使用帶charset(字符編碼)參數的構造器來構建字符串對象,或者使用系統平臺默認的字符集編碼
- *
- * @param ascii 用來轉換成字符串的ASCII碼的字節數組
- * @param hibyte 每16位的Unicode編碼單元的前8位
- * @param offset 截取ASCII碼的字節數組的起始偏移量
- * @param count 在ASCII碼的字節數組中截取的元素長度
- *
- * @throws IndexOutOfBoundsException 如果offset或count參數越界了,那麼會拋出此異常
- *
- * @see #String(byte[], int)
- * @see #String(byte[], int, int, java.lang.String)
- * @see #String(byte[], int, int, java.nio.charset.Charset)
- * @see #String(byte[], int, int)
- * @see #String(byte[], java.lang.String)
- * @see #String(byte[], java.nio.charset.Charset)
- * @see #String(byte[])
- */
- @Deprecated
- public String(byte ascii[], int hibyte, int offset, int count) {
- checkBounds(ascii, offset, count);
- char value[] = new char[count];
- //高8位如果是零,說明是正數
- if (hibyte == 0) {
- for (int i = count; i-- > 0;) {
- //因爲byte的取值範圍是 -128~127,而Char是0~65535
- //所以需要將前8位全部清爲零,從而使得byte原來的負值變成正值
- //0xff的二進制爲1111 1111
- value[i] = (char)(ascii[i + offset] & 0xff);
- }
- } else {
- // <<=帶符號的左移動運算,向左移動8位,則最右邊的8位全部清零
- hibyte <<= 8;
- for (int i = count; i-- > 0;) {
- value[i] = (char)(hibyte | (ascii[i + offset] & 0xff));
- }
- }
- this.value = value;
- }
- /**
- * 通過傳入一個ASCII碼的字節數組來構建一個新的字符串對象,
- * 直接從offset偏移量位置截取到字節數組的末尾
- * @param ascii 用來轉換成字符串的ASCII碼的字節數組
- * @param hibyte 每16位的Unicode編碼單元的前8位
- */
- @Deprecated
- public String(byte ascii[], int hibyte) {
- this(ascii, hibyte, 0, ascii.length);
- }
- /**
- * 檢查offset,count參數在字節數組中是否越界的工具方法
- * @param bytes 目標字節數組
- * @param offset 起始偏移量
- * @param length 截取長度
- */
- private static void checkBounds(byte[] bytes, int offset, int length) {
- if (length < 0)
- throw new StringIndexOutOfBoundsException(length);
- if (offset < 0)
- throw new StringIndexOutOfBoundsException(offset);
- if (offset > bytes.length - length)
- throw new StringIndexOutOfBoundsException(offset + length);
- }
- /**
- * 通過StringCoding類的decode方法將指定的字節數組按照指定的字符集編碼
- * 解碼爲一個字符串對象
- * @param bytes 字節數組
- * @param offset 截取起始偏移量
- * @param length 截取的長度
- * @param charsetName 字符集編碼
- * @throws UnsupportedEncodingException
- */
- public String(byte bytes[], int offset, int length, String charsetName)
- throws UnsupportedEncodingException {
- if (charsetName == null)
- throw new NullPointerException("charsetName");
- checkBounds(bytes, offset, length);
- this.value = StringCoding.decode(charsetName, bytes, offset, length);
- }
- /**
- * 通過StringCoding類的decode方法將指定的字節數組按照指定的字符集編碼
- * 解碼爲一個字符串對象
- * @param bytes 字節數組
- * @param offset 截取起始偏移量
- * @param length 截取的長度
- * @param charset 字符集編碼對象
- */
- public String(byte bytes[], int offset, int length, Charset charset) {
- if (charset == null)
- throw new NullPointerException("charset");
- checkBounds(bytes, offset, length);
- this.value = StringCoding.decode(charset, bytes, offset, length);
- }
- /**
- * 通過StringCoding類的decode方法將指定的字節數組按照指定的字符集編碼
- * 解碼爲一個字符串對象(重載)
- *
- * @since JDK1.1
- */
- public String(byte bytes[], String charsetName)
- throws UnsupportedEncodingException {
- this(bytes, 0, bytes.length, charsetName);
- }
- /**
- * 通過StringCoding類的decode方法將指定的字節數組按照指定的字符集編碼
- * 解碼爲一個字符串對象(重載)
- * @since 1.6
- */
- public String(byte bytes[], Charset charset) {
- this(bytes, 0, bytes.length, charset);
- }
- /**
- * 通過StringCoding類的decode方法將指定的字節數組按照系統平臺
- * 的默認字符集編碼解碼爲一個字符串對象(重載)
- * @since 1.6
- */
- public String(byte bytes[], int offset, int length) {
- checkBounds(bytes, offset, length);
- this.value = StringCoding.decode(bytes, offset, length);
- }
- /**
- * 通過StringCoding類的decode方法將指定的字節數組按照系統平臺
- * 的默認字符集編碼解碼爲一個字符串對象(重載)
- * 這裏沒有指定offset,count參數,則默認會直接截取[0,length() -1]範圍內的字節即
- * 默認會直接將整個字節數組解碼爲一個新的字符串對象
- * @since 1.6
- */
- public String(byte bytes[]) {
- this(bytes, 0, bytes.length);
- }
- /**
- * 根據傳入的StringBuffer對象構造一個新的String對象,內部會將StringBuffer對象
- * 內的字符數組都複製到當前對象的value屬性上,注意此方法是加鎖的即線程安全的。
- * @param buffer
- */
- public String(StringBuffer buffer) {
- synchronized(buffer) {
- this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
- }
- }
- /**
- * 根據傳入的StringBuilder對象構造一個新的String對象,內部會將StringBuilder對象
- * 內的字符數組都複製到當前對象的value屬性上,注意此方法不是線程安全的。
- * @since 1.5
- */
- public String(StringBuilder builder) {
- this.value = Arrays.copyOf(builder.getValue(), builder.length());
- }
- String(char[] value, boolean share) {
- this.value = value;
- }
- /**
- * 私有構造函數,建議使用String(char[],int,int)構造函數代替,
- * 此構造函數已被標記爲廢棄
- */
- @Deprecated
- String(int offset, int count, char[] value) {
- this(value, offset, count);
- }
- /**
- * 返回一個字符串的長度,此長度必須等於Unicode編碼單元的長度。
- * 一個Unicode編碼單元爲16個bit,而一個char字符佔2個字節剛好16個bit,即
- * 一個字符串的長度等於它包含的字符個數。
- *
- * @return 返回當前字符串的長度
- */
- public int length() {
- return value.length;
- }
- /**
- * 判斷一個字符串是否爲一個空字符串[""]
- * 當且僅當字符串的length()等於零,此方法才返回true,否則返回false
- *
- * @since 1.6
- */
- public boolean isEmpty() {
- return value.length == 0;
- }
- /**
- * 返回字符串某個索引位置的字符
- *
- * @param index 字符的索引位置,從零開始計算
- * @return 返回指定索引位置的字符
- * @exception IndexOutOfBoundsException
- * 若index參數爲負數或者index參數不小於length(),則會拋出索引越界異常
- */
- public char charAt(int index) {
- if ((index < 0) || (index >= value.length)) {
- throw new StringIndexOutOfBoundsException(index);
- }
- return value[index];
- }
- /**
- * 返回字符串某個索引位置的Unicode code point(Unicode代碼點)
- *
- * @param index 字符的索引位置,從零開始計算
- * @return 返回指定索引位置的Unicode code point(Unicode代碼點)
- * @exception IndexOutOfBoundsException
- * 若index參數爲負數或者index參數不小於length(),則會拋出索引越界異常
- * @since 1.5
- */
- public int codePointAt(int index) {
- if ((index < 0) || (index >= value.length)) {
- throw new StringIndexOutOfBoundsException(index);
- }
- return Character.codePointAtImpl(value, index, value.length);
- }
- /**
- * 返回字符串某個索引位置之前的Unicode code point(Unicode代碼點)
- *
- * @param index 字符的索引位置,從零開始計算
- * @return 返回指定索引位置之前的Unicode code point(Unicode代碼點)
- * @exception IndexOutOfBoundsException
- * 若index參數小於1或者大於length(),則會拋出索引越界異常
- * @since 1.5
- */
- public int codePointBefore(int index) {
- int i = index - 1;
- if ((i < 0) || (i >= value.length)) {
- throw new StringIndexOutOfBoundsException(index);
- }
- return Character.codePointBeforeImpl(value, index, 0);
- }
- /**
- * 返回字符串的指定區間內的Unicode code point(Unicode代碼點)的總個數
- *
- * @param beginIndex 起始索引位置
- * @param endIndex 結束索引位置
- * @return 返回指定區間範圍內的Unicode代碼點的總個數
- * @exception IndexOutOfBoundsException
- * 若beginIndex參數爲負數或endIndex參數大於length(),
- * 或者beginIndex參數大於endIndex參數,則會拋出索引越界異常
- * @since 1.5
- */
- public int codePointCount(int beginIndex, int endIndex) {
- if (beginIndex < 0 || endIndex > value.length || beginIndex > endIndex) {
- throw new IndexOutOfBoundsException();
- }
- return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
- }
- /**
- * index索引位置的字符往後偏移codePointOffset個索引位置,返回偏移後的索引位置
- *
- * @param index 某個字符的索引位置,是個基準點
- * @param codePointOffset Unicode代碼點的偏移量
- * @return index 返回index索引位置偏移codePointOffset個Unicode代碼點後新的索引位置
- * @exception IndexOutOfBoundsException
- * 若index參數爲負數或大於length()或positive是正數且
- * index索引位置後面的子字符串包含的Unicode代碼點個數
- * 小於codePointOffset或codePointOffset是負數且index索引位置前面的
- * 子字符串包含的Unicode代碼點個數小於codePointOffset參數的絕對值,
- * 則會拋出索引位置越界異常
- * @since 1.5
- */
- public int offsetByCodePoints(int index, int codePointOffset) {
- if (index < 0 || index > value.length) {
- throw new IndexOutOfBoundsException();
- }
- return Character.offsetByCodePointsImpl(value, 0, value.length,
- index, codePointOffset);
- }
- /**
- * 將當前字符串的字符複製到另一個目標字符數組中
- * @param dst 目標字符數組
- * @param dstBegin 複製的字符從目標字符數組的哪個索引位置開始放入
- */
- void getChars(char dst[], int dstBegin) {
- System.arraycopy(value, 0, dst, dstBegin, value.length);
- }
- /**
- * 將當前字符串的[srcBegin,srcEnd)區間內的字符複製到dst[]目標字符數組內
- * dstbegin + (srcEnd-srcBegin) - 1
- *
- * @param srcBegin 從原字符串的字符數組的哪個索引位置開始複製
- * @param srcEnd 從原字符串的字符數組的哪個索引位置開始結束複製
- * @param dst 字符複製到的哪個目標字符數組
- * @param dstBegin 複製的字符從目標字符數組的哪個索引位置開始放入
- * @exception IndexOutOfBoundsException
- * 若srcBegin參數爲負數或
- * srcBegin參數大於srcEnd參數或
- * srcEnd大於length()或
- * dstBegin參數爲負數或
- * dstBegin + (srcEnd - srcBegin)表達式計算值大於dst.length(),
- * 則會拋出索引位置越界異常
- */
- 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);
- }
- /**
- * 將字符串的包含字符複製到一個目標的字節數組中。每個字節接收對應字符的低8位,
- * 而每個字符的高8位則不會被複制,也不會參與以任何方式的轉換
- *
- * @deprecated 此方法不能準確的將字符轉換成byte字節數組。
- * 自JDK1.1版本起,推薦使用String的getBytes()方法來代替,
- * getBytes()方法默認會使用系統平臺的默認字符集編碼
- *
- * @param srcBegin 從原字符串的字符數組的哪個索引位置開始複製
- * @param srcEnd 從原字符串的字符數組的哪個索引位置開始結束複製
- * @param dst 字符複製到的哪個目標字節數組
- * @param dstBegin 複製的字符從目標字節數組的哪個索引位置開始放入
- * @exception IndexOutOfBoundsException
- * 若srcBegin參數爲負數或
- * srcBegin參數大於srcEnd參數或
- * srcEnd大於length()或
- * dstBegin參數爲負數或
- * dstBegin + (srcEnd - srcBegin)表達式計算值大於dst.length(),
- * 則會拋出索引位置越界異常
- */
- @Deprecated
- public void getBytes(int srcBegin, int srcEnd, byte 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);
- }
- int j = dstBegin;
- int n = srcEnd;
- int i = srcBegin;
- /** 避免直接操作類的屬性,使用方法中的局部變量代替引用可以減少getfield操作的次數,提高性能*/
- char[] val = value;
- while (i < n) {
- dst[j++] = (byte)val[i++];
- }
- }
- /**
- * 使用指定的字符集編碼將String對象編碼成一個字節數組
- * 若charsetName參數未指定,那麼內部會拋出NullPointerException異常
- * 如果你想要更詳細的控制字符編碼的處理過程,那麼你需要使用{@link java.nio.charset.CharsetEncoder}類
- *
- * @param charsetName
- * {@linkplain java.nio.charset.Charset}類支持的字符集編碼名稱
- * @return 返回String對象編碼後的字節數組
- * @throws UnsupportedEncodingException
- * charset參數表示的不是合法的字符集編碼名稱,
- * 那麼會拋出UnsupportedEncodingException異常
- *
- * @since JDK1.1
- */
- public byte[] getBytes(String charsetName)
- throws UnsupportedEncodingException {
- if (charsetName == null) throw new NullPointerException();
- return StringCoding.encode(charsetName, value, 0, value.length);
- }
- /**
- * 方法同上,只是字符集編碼參數改成了通過Charset類來提供
- *
- * @since 1.6
- */
- public byte[] getBytes(Charset charset) {
- if (charset == null) throw new NullPointerException();
- return StringCoding.encode(charset, value, 0, value.length);
- }
- /**
- * 同getBytes(String charsetName)方法類似,只是這裏是採用系統平臺默認的字符集編碼
- * 對字符串進行編碼
- *
- * @since JDK1.1
- */
- public byte[] getBytes() {
- return StringCoding.encode(value, 0, value.length);
- }
- /**
- * 比較兩個對象是否相等,當且僅當anObject參數不爲null且
- * 它與當前字符串對象表示的是同一個字符序列,纔會返回true
- *
- * @param anObject 與當前字符串對象進行比較的對象
- * @return 返回指定對象是否與當前字符串對象相等
- *
- * @see #compareTo(String)
- * @see #equalsIgnoreCase(String)
- */
- public boolean equals(Object anObject) {
- if (this == anObject) {
- return true;
- }
- //若anObject對象是String類型
- if (anObject instanceof String) {
- //強制轉換成String對象
- String anotherString = (String) anObject;
- //獲取當前字符串對象的字符序列並緩存到變量n上
- int n = value.length;
- //若兩者的字符序列長度一致,則接下來要比較字符序列的每個字符是否相等
- if (n == anotherString.value.length) {
- char v1[] = value;
- char v2[] = anotherString.value;
- int i = 0;
- while (n-- != 0) {
- //只要字符序列中存在一個字符不相等,則返回false即兩者不相等
- if (v1[i] != v2[i]) {
- return false;
- }
- i++;
- }
- return true;
- }
- }
- return false;
- }
- /**
- * 比較當前字符串的字符序列是否與指定的StringBuffer對象包含的字符序列相等
- *
- * @param sb 與當前字符串對象進行比較的StringBuffer對象
- * @return 返回當前字符串對象是否與指定的StringBuffer對象相等
- *
- * @since 1.4
- */
- public boolean contentEquals(StringBuffer sb) {
- synchronized (sb) {
- return contentEquals((CharSequence) sb);
- }
- }
- /**
- * 比較當前字符串的字符序列是否與指定的CharSequence對象包含的字符序列相等
- * @since 1.5
- */
- public boolean contentEquals(CharSequence cs) {
- if (value.length != cs.length())
- return false;
- // 若傳入的參數是StringBuffer或StringBuilder類型
- if (cs instanceof AbstractStringBuilder) {
- char v1[] = value;
- char v2[] = ((AbstractStringBuilder) cs).getValue();
- int i = 0;
- int n = value.length;
- while (n-- != 0) {
- if (v1[i] != v2[i])
- return false;
- i++;
- }
- return true;
- }
- // 若傳入的參數是String類型
- if (cs.equals(this))
- return true;
- // 若傳入的參數是通用的CharSequence類型
- char v1[] = value;
- int i = 0;
- int n = value.length;
- while (n-- != 0) {
- if (v1[i] != cs.charAt(i))
- return false;
- i++;
- }
- return true;
- }
- /**
- * 比較當前字符串的字符序列是否與指定的String對象包含的字符序列相等,
- * 此方法在比較過程中會忽略每個字符的大小寫
- *
- * 當兩個字符串c1和c2滿足如下其中任意一個條件,則認爲兩者在忽略大小寫的情況下相等:
- * 1. c1 == c2 返回true
- * 2. 對於兩個字符串包含的字符序列中的每個字符調用java.lang.Character#toUpperCase(char)方法,
- * 若最終生成的結果相同,則認爲兩者相等
- * 3. 對於兩個字符串包含的字符序列中的每個字符調用java.lang.Character#toLowerCase(char)方法,
- * 若最終生成的結果相同,則認爲兩者相等
- * @param anotherString 與當前字符串對象進行比較的字符串對象
- * @return 返回兩個字符串對象是否相等
- *
- * @see #equals(Object)
- */
- public boolean equalsIgnoreCase(String anotherString) {
- return (this == anotherString) ? true
- : (anotherString != null)
- && (anotherString.value.length == value.length)
- && regionMatches(true, 0, anotherString, 0, value.length);
- }
- /**
- * 比較兩個字符串的字母順序
- * 這個比較操作是基於字符串對象的字符序列中包含的每個字符的Unicode值進行比較。
- * 如果當前字符串對象的字母順序在字符串參數之前,那麼返回結果爲負數,
- * 如果當前字符串對象的字母順序在字符串參數之後,那麼返回結果爲正數,
- * 如果當前字符串對象與字符串參數相等(即equals()返回true),那麼返回結果爲零
- *
- * @param anotherString the <code>String</code> to be compared.
- * @return 返回兩個字符串的比較結果,
- * 正數表示當前字符串較大,負數表示當前字符串較小,否則表達兩者相等
- */
- public int compareTo(String anotherString) {
- int len1 = value.length;
- int len2 = anotherString.value.length;
- //取兩個字符串長度較小的那個長度
- int lim = Math.min(len1, len2);
- char v1[] = value;
- char v2[] = anotherString.value;
- int k = 0;
- while (k < lim) {
- char c1 = v1[k];
- char c2 = v2[k];
- if (c1 != c2) {
- return c1 - c2;
- }
- k++;
- }
- // 如果前lim個字符全部相等,那麼此時就比較誰的字符串長度大,
- // 判定長度大的字符串比長度小的字符串大
- return len1 - len2;
- }
- /**
- * 字符串忽略大小寫比較器,此比較器實現了Serializable接口
- * 注意:此接口並沒有考慮語言環境,對於部分地區可能會導致不滿意的順序,
- * java.text包下的Collators類提供了語言環境敏感的字符串順序。
- *
- * @see java.text.Collator#compare(String, String)
- * @since 1.2
- */
- public static final Comparator<String> CASE_INSENSITIVE_ORDER
- = new CaseInsensitiveComparator();
- private static class CaseInsensitiveComparator
- implements Comparator<String>, java.io.Serializable {
- private static final long serialVersionUID = 8575799808933029326L;
- public int compare(String s1, String s2) {
- int n1 = s1.length();
- int n2 = s2.length();
- int min = Math.min(n1, n2);
- for (int i = 0; i < min; i++) {
- char c1 = s1.charAt(i);
- char c2 = s2.charAt(i);
- if (c1 != c2) {
- c1 = Character.toUpperCase(c1);
- c2 = Character.toUpperCase(c2);
- if (c1 != c2) {
- c1 = Character.toLowerCase(c1);
- c2 = Character.toLowerCase(c2);
- if (c1 != c2) {
- // 因爲存在數字晉升機制,因此此處不會存在數據類型溢出問題
- return c1 - c2;
- }
- }
- }
- }
- return n1 - n2;
- }
- }
- /**
- * 忽略大小寫前提下比較兩個字符串的字母順序
- * 注意:此接口並沒有考慮語言環境,對於部分地區可能會導致不滿意的順序,
- * java.text包下的Collators類提供了語言環境敏感的字符串順序。
- *
- * @param str 與當前字符串對象進行邊角的字符串參數
- * @return
- * 返回負數表示指定的字符串對象大於當前字符串對象
- * 返回正數表示指定的字符串對象小於當前字符串對象
- * 返回零表示指定的字符串對象等於當前字符串對象
- * @see java.text.Collator#compare(String, String)
- * @since 1.2
- */
- public int compareToIgnoreCase(String str) {
- return CASE_INSENSITIVE_ORDER.compare(this, str);
- }
- /**
- * 比較兩個字符串的指定區域內的字符序列是否相等
- * 注意:此方法並沒有忽略字符大小寫
- * @param toffset 當前字符串截取的起始索引位置
- * @param other 傳入的另一個字符串對象
- * @param ooffset other參數表示的字符串對象的起始索引位置
- * @param len other參數表示的字符串對象的截取長度
- * @return 返回兩個字符串的指定區域內的字符序列是否相等
- */
- public boolean regionMatches(int toffset, String other, int ooffset,
- int len) {
- char ta[] = value;
- int to = toffset;
- char pa[] = other.value;
- int po = ooffset;
- // Note: toffset, ooffset, or len might be near -1>>>1.
- if ((ooffset < 0) || (toffset < 0)
- || (toffset > (long)value.length - len)
- || (ooffset > (long)other.value.length - len)) {
- return false;
- }
- while (len-- > 0) {
- if (ta[to++] != pa[po++]) {
- return false;
- }
- }
- return true;
- }
- /**
- * 比較兩個字符串的指定區域內的字符序列是否相等
- * 當且僅當滿足以下其中任意一個提交,
- * 則判定兩個字符串的指定區域內的字符序列不相等:
- * 1. toffset參數爲負數
- * 2. ooffset參數爲負數
- * 3. toffset + len大於當前字符串的長度
- * 4. ooffset + len大於other參數表示的字符串的長度
- * 5. ignoreCase=false且存在某些非負數K小於參數len,
- * 比如:this.charAt(toffset + k) != other.charAt(ooffset + k)
- * 6. ignoreCase=true且存在某些非負數K小於參數len,
- * 比如: Character.toLowerCase(this.charAt(toffset + k)) !=
- * Character.toLowerCase(other.charAt(ooffset + k))
- *
- * Character.toLowerCase(this.charAt(toffset+k)) !=
- * Character.toLowerCase(other.charAt(ooffset+k))
- *
- * Character.toUpperCase(this.charAt(toffset + k)) !=
- * Character.toUpperCase(other.charAt(ooffset + k))
- *
- * @param ignoreCase 比較過程中是否忽略大小寫
- * @param toffset 當前字符串截取的起始索引位置
- * @param other 傳入的另一個字符串對象
- * @param ooffset other參數表示的字符串對象的起始索引位置
- * @param len other參數表示的字符串對象的截取長度
- * @return 返回兩個字符串的指定區域內的字符序列是否相等
- */
- public boolean regionMatches(boolean ignoreCase, int toffset,
- String other, int ooffset, int len) {
- char ta[] = value;
- int to = toffset;
- char pa[] = other.value;
- int po = ooffset;
- // Note: toffset, ooffset, or len might be near -1>>>1.
- if ((ooffset < 0) || (toffset < 0)
- || (toffset > (long)value.length - len)
- || (ooffset > (long)other.value.length - len)) {
- return false;
- }
- while (len-- > 0) {
- char c1 = ta[to++];
- char c2 = pa[po++];
- //如果兩個字符相等,則跳過
- if (c1 == c2) {
- continue;
- }
- //如果兩個字符不相等,則要判斷是否設置了忽略大小寫
- if (ignoreCase) {
- // 如果設置了忽略大小寫,那麼首先將兩者統一轉成大寫再比較
- char u1 = Character.toUpperCase(c1);
- char u2 = Character.toUpperCase(c2);
- //若轉成大寫後兩者相等,那麼跳過,繼續比較下一個字符
- if (u1 == u2) {
- continue;
- }
- //非常不幸的是,Character.toUpperCase()在轉換成大寫時對於格魯吉亞字母不能正常工作,
- //因爲格魯吉亞字母擁有怪異的大小寫轉換規則,因此我們需要在當前循環退出之前再進行一次字符比較檢查
- if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
- continue;
- }
- }
- // 若兩個字符本身不相等且ignoreCase=false或
- // 兩個字符本身不相等且ignoreCase=true,但是統一轉換成大寫形式後仍然不相等,
- // 此時應該返回false,即判定兩個字符不相等
- return false;
- }
- //否則判定兩個字符串的指定區域內的字符序列相等
- return true;
- }
- /**
- * 檢測當前字符串是否以指定的前綴字符串開頭
- * 此方法等價於this.substring(toffset).startsWith(prefix)
- * @param prefix 指定的字符串前綴
- * @param toffset 起始偏移量
- * @return 若toffset參數爲負數或者大於當前字符串的長度,則直接返回false
- */
- public boolean startsWith(String prefix, int toffset) {
- char ta[] = value;
- int to = toffset;
- char pa[] = prefix.value;
- int po = 0;
- int pc = prefix.value.length;
- // 若toffset爲負數或toffset + prefix.length() > this.length(),則直接return false
- if ((toffset < 0) || (toffset > value.length - pc)) {
- return false;
- }
- while (--pc >= 0) {
- if (ta[to++] != pa[po++]) {
- return false;
- }
- }
- return true;
- }
- /**
- * 檢測當前字符串是否以指定的前綴字符串開頭(重載)
- * @param prefix 指定的字符串前綴
- * @since 1. 0
- */
- public boolean startsWith(String prefix) {
- return startsWith(prefix, 0);
- }
- /**
- * 檢測當前字符串是否以指定的後綴字符串結尾
- *
- * @param suffix 後綴字符串
- */
- public boolean endsWith(String suffix) {
- return startsWith(suffix, value.length - suffix.value.length);
- }
- /**
- * 計算當前字符串的hashcode值,計算公式爲:
- * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
- * 上面的n表示字符串的長度,^表示求冪運算
- * 空字符串""的hashcode值爲零
- *
- * @return 返回當前字符串對象的hashcode值
- */
- 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;
- }
- /**
- * 返回指定字符在當前字符串對象中第一次出現的索引位置
- *
- * @param ch Unicode code point表示的一個字符,取值範圍爲[0, 0xFFFF)
- * @return 若指定字符在當前字符串的字符序列中不存在,則返回-1
- */
- public int indexOf(int ch) {
- return indexOf(ch, 0);
- }
- /**
- * 返回指定字符在當前字符串對象中第一次出現的索引位置
- *
- * @param ch Unicode code point表示的一個字符,取值範圍爲[0, 0xFFFF)
- * @param fromIndex 在當前字符串中查找的起始索引位置
- * @return 若指定字符在當前字符串的字符序列中不存在,則返回-1
- */
- public int indexOf(int ch, int fromIndex) {
- final int max = value.length;
- if (fromIndex < 0) {
- fromIndex = 0;
- } else if (fromIndex >= max) {
- return -1;
- }
- //若ch參數小於Unicode補充代碼點的最小值0x010000
- if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
- // 查理大部分情況,比如ch參數是一個合法的BMP代碼點,
- // 或者ch是一個負數即非法的代碼點
- final char[] value = this.value;
- for (int i = fromIndex; i < max; i++) {
- if (value[i] == ch) {
- return i;
- }
- }
- return -1;
- } else {
- //字符屬於Unicode補充代碼點情況
- return indexOfSupplementary(ch, fromIndex);
- }
- }
- /**
- * 返回指定的代碼點表示的字符在當前字符串中第一次出現的索引位置
- * @param fromIndex 從哪個索引位置開始查找
- */
- private int indexOfSupplementary(int ch, int fromIndex) {
- if (Character.isValidCodePoint(ch)) {
- final char[] value = this.value;
- /**
- * 一個完整的Unicode字符叫代碼點CodePoint,而一個Java char叫代碼單元code unit。
- * String對象以UTF-16保存Unicode字符,需要用2個字符表示一個超大字符集的漢字,
- * 這這種表示方式稱之爲Surrogate,第一個字符叫 Surrogate High,第二個就是 Surrogate Low
- */
- final char hi = Character.highSurrogate(ch);
- final char lo = Character.lowSurrogate(ch);
- final int max = value.length - 1;
- for (int i = fromIndex; i < max; i++) {
- if (value[i] == hi && value[i + 1] == lo) {
- return i;
- }
- }
- }
- return -1;
- }
- /**
- * 返回指定代碼點表示的字符在當前字符串對象中最後一次出現的索引位置
- */
- public int lastIndexOf(int ch) {
- return lastIndexOf(ch, value.length - 1);
- }
- /**
- * 返回指定的代碼點表示的字符在當前字符串中最後一次出現的索引位置
- * 與indexOf方法類似
- */
- public int lastIndexOf(int ch, int fromIndex) {
- if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
- final char[] value = this.value;
- int i = Math.min(fromIndex, value.length - 1);
- for (; i >= 0; i--) {
- if (value[i] == ch) {
- return i;
- }
- }
- return -1;
- } else {
- return lastIndexOfSupplementary(ch, fromIndex);
- }
- }
- /**
- * 處理補充字符的最後一次出現索引位置計算
- */
- private int lastIndexOfSupplementary(int ch, int fromIndex) {
- if (Character.isValidCodePoint(ch)) {
- final char[] value = this.value;
- char hi = Character.highSurrogate(ch);
- char lo = Character.lowSurrogate(ch);
- int i = Math.min(fromIndex, value.length - 2);
- for (; i >= 0; i--) {
- if (value[i] == hi && value[i + 1] == lo) {
- return i;
- }
- }
- }
- return -1;
- }
- /**
- * indexOf方法的重載
- */
- public int indexOf(String str) {
- return indexOf(str, 0);
- }
- /**
- * 返回指定字符串在當前字符串對象中第一次出現的索引位置
- */
- public int indexOf(String str, int fromIndex) {
- return indexOf(value, 0, value.length,
- str.value, 0, str.value.length, fromIndex);
- }
- /**
- * 返回指定目標字符數組的[targetOffset,targetOffset + targetCount]區間內字符序列
- * 在源字符數組的[sourceOffset,sourceOffset + sourceCount]區間內字符序列中
- * 第一次出現的索引位置
- *
- * @param source 待搜索的源字符數組
- * @param sourceOffset 源字符數組搜索的起始偏移量
- * @param sourceCount 源字符數組從起始偏移量位置開始往後搜索的字符個數
- * @param target 待搜索的目標字符數組
- * @param targetOffset 目標字符數組搜索的起始偏移量
- * @param targetCount 目標字符數組從起始偏移量位置開始往後搜索的字符個數
- * @param fromIndex 開始搜索的起始索引位置
- */
- static int indexOf(char[] source, int sourceOffset, int sourceCount,
- char[] target, int targetOffset, int targetCount,
- int fromIndex) {
- if (fromIndex >= sourceCount) {
- return (targetCount == 0 ? sourceCount : -1);
- }
- if (fromIndex < 0) {
- fromIndex = 0;
- }
- if (targetCount == 0) {
- return fromIndex;
- }
- char first = target[targetOffset];
- int max = sourceOffset + (sourceCount - targetCount);
- for (int i = sourceOffset + fromIndex; i <= max; i++) {
- /* 查找第一個字符 */
- if (source[i] != first) {
- while (++i <= max && source[i] != first);
- }
- if (i <= max) {
- int j = i + 1;
- int end = j + targetCount - 1;
- for (int k = targetOffset + 1; j < end && source[j]
- == target[k]; j++, k++);
- if (j == end) {
- /* 到底目標字符結尾 */
- return i - sourceOffset;
- }
- }
- }
- return -1;
- }
- /**
- * 返回指定字符串在當前字符串對象中的最後一次出現的索引位置
- */
- public int lastIndexOf(String str) {
- return lastIndexOf(str, value.length);
- }
- /**
- * 返回指定字符串在當前字符串對象中的最後一次出現的索引位置,
- * 在當前字符串上從指定的fromIndex索引位置開始搜索
- */
- public int lastIndexOf(String str, int fromIndex) {
- return lastIndexOf(value, 0, value.length,
- str.value, 0, str.value.length, fromIndex);
- }
- /**
- * 返回指定目標字符數組的[targetOffset,targetOffset + targetCount]區間內字符序列
- * 在源字符數組的[sourceOffset,sourceOffset + sourceCount]區間內字符序列中
- * 最後一次出現的索引位置
- *
- * @param source 待搜索的源字符數組
- * @param sourceOffset 源字符數組搜索的起始偏移量
- * @param sourceCount 源字符數組從起始偏移量位置開始往後搜索的字符個數
- * @param target 待搜索的目標字符數組
- * @param targetOffset 目標字符數組搜索的起始偏移量
- * @param targetCount 目標字符數組從起始偏移量位置開始往後搜索的字符個數
- * @param fromIndex 開始搜索的起始索引位置
- */
- static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
- char[] target, int targetOffset, int targetCount,
- int fromIndex) {
- int rightIndex = sourceCount - targetCount;
- if (fromIndex < 0) {
- return -1;
- }
- if (fromIndex > rightIndex) {
- fromIndex = rightIndex;
- }
- /* 若targetCount==0,則直接返回fromIndex */
- if (targetCount == 0) {
- return fromIndex;
- }
- int strLastIndex = targetOffset + targetCount - 1;
- char strLastChar = target[strLastIndex];
- int min = sourceOffset + targetCount - 1;
- int i = min + fromIndex;
- startSearchForLastChar:
- while (true) {
- while (i >= min && source[i] != strLastChar) {
- i--;
- }
- if (i < min) {
- return -1;
- }
- int j = i - 1;
- int start = j - (targetCount - 1);
- int k = strLastIndex - 1;
- while (j > start) {
- if (source[j--] != target[k--]) {
- i--;
- continue startSearchForLastChar;
- }
- }
- return start - sourceOffset + 1;
- }
- }
- /**
- * 從beginIndex參數表示的索引位置開始截取當前字符串對象
- * 若beginIndex=0,則直接返回當前字符串對象,否則截取生成一個子字符串對象
- */
- public String substring(int beginIndex) {
- if (beginIndex < 0) {
- throw new StringIndexOutOfBoundsException(beginIndex);
- }
- int subLen = value.length - beginIndex;
- if (subLen < 0) {
- throw new StringIndexOutOfBoundsException(subLen);
- }
- return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
- }
- /**
- * 截取[beginIndex,endIndex)之間的字符串
- * 最終生成的子字符串的長度爲endIndex - beginIndex
- *
- * @param beginIndex 截取的起始索引位置,包含在內
- * @param endIndex 截取的結束索引位置,不包含在內
- * @return 返回截取的子字符串對象
- * @exception IndexOutOfBoundsException 如果
- * beginIndex爲負數或
- * endIndex > length()或
- * beginIndex > endIndex,則會拋出索引越界異常
- */
- 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);
- }
- /**
- * 截取[beginIndex,endIndex)之間的字符串,最終生成CharSequence對象
- * 與substring(int beginIndex, int endIndex)方法類似,區別就是返回值類型不同
- *
- * @param beginIndex 截取的起始索引位置,包含在內
- * @param endIndex 截取的結束索引位置,不包含在內
- * @return 返回截取的CharSequence對象
- * @exception IndexOutOfBoundsException 如果
- * beginIndex爲負數或
- * endIndex > length()或
- * beginIndex > endIndex,則會拋出索引越界異常
- */
- public CharSequence subSequence(int beginIndex, int endIndex) {
- return this.substring(beginIndex, endIndex);
- }
- /**
- * 將指定的字符串拼接到當前字符串的末尾
- * 若str參數表示的字符串的長度==0,那麼直接返回this,否則會創建一個新的字符串對象,比如:
- * "cares".concat("s") returns "caress"
- * "to".concat("get").concat("her") returns "together"
- *
- * @param str 需要拼接到當前字符串末尾的字符串對象
- * @return 返回拼接後的字符串對象
- */
- public String concat(String str) {
- int otherLen = str.length();
- if (otherLen == 0) {
- return this;
- }
- int len = value.length;
- char buf[] = Arrays.copyOf(value, len + otherLen);
- str.getChars(buf, len);
- return new String(buf, true);
- }
- /**
- * 替換當前字符串對象中所有出現的oldChar字符爲newChar字符,最終
- * 返回一個新的字符串對象
- * 若當前字符串對象中不包含oldChar字符,那麼直接return this,否則,
- * 會生成一個新的字符串對象並返回
- * 示例:
- * "mesquite in your cellar".replace('e', 'o')
- * returns "mosquito in your collar"
- * "the war of baronets".replace('r', 'y')
- * returns "the way of bayonets"
- * "sparring with a purple porpoise".replace('p', 't')
- * returns "starring with a turtle tortoise"
- * "JonL".replace('q', 'x')
- * returns "JonL" (無變化)
- * @param oldChar 被替換的舊字符
- * @param newChar 替換的新字符
- * @return 返回替換指定字符後新的字符串對象
- */
- public String replace(char oldChar, char newChar) {
- //若被替換字符與替換字符不相等纔會執行下面的操作,否則直接return this.
- if (oldChar != newChar) {
- int len = value.length;
- int i = -1;
- char[] val = value; /* 避免直接操作value屬性 */
- //從索引位置零開始查找當前字符串中第一次出現字符oldChar的索引位置
- while (++i < len) {
- if (val[i] == oldChar) {
- break;
- }
- }
- // 若查找到oldChar在當前字符串中第一次出現的索引位置 < length(),
- // 否則就沒有字符替換的意義了
- if (i < len) {
- //將[0,i)直接的字符緩存到char[]字符數組中
- char buf[] = new char[len];
- for (int j = 0; j < i; j++) {
- buf[j] = val[j];
- }
- //遍歷[i,length() - 1]之間的字符
- while (i < len) {
- //獲取遍歷到的每個字符
- char c = val[i];
- // 若當前遍歷到的字符與oldChar相等,則把當前遍歷到的字符替換爲newChar,
- // 否則當前遍歷到的字符保持不變,然後將其存入char[]字符數組中
- buf[i] = (c == oldChar) ? newChar : c;
- i++;
- }
- // 最終根據臨時變量char[]字符數組構造一個新的字符串對象並返回
- return new String(buf, true);
- }
- }
- return this;
- }
- /**
- * 檢測當前字符串是否符合給定的正則表達式
- *
- * @param regex 當前字符串對象用來匹配的正則表達式
- * @return 當且僅當當前字符串匹配給定的正則表達式纔會返回true
- * @throws PatternSyntaxException
- * 若給定的正則表達式語法錯誤會拋出此異常
- *
- * @see java.util.regex.Pattern
- *
- * @since 1.4
- * @spec JSR-51
- */
- public boolean matches(String regex) {
- return Pattern.matches(regex, this);
- }
- /**
- * 當且僅當當前字符串包含指定的字符序列纔會返回true
- * Returns true if and only if this string contains the specified
- * sequence of char values.
- *
- * @param s 給定的字符序列對象
- * @return true 若當前字符串包含給定的參數s表示的字符序列時返回true
- * @throws NullPointerException 若參數s表示的字符串對象爲null,則會拋出NullPointerException異常
- * @since 1.5
- */
- public boolean contains(CharSequence s) {
- return indexOf(s.toString()) > -1;
- }
- /**
- * 根據給定的正則表達式替換當前字符串匹配到的第一個子字符串爲參數replacement表示的字符串
- * 注意:replacement參數中若包含反斜槓\和美元符號$可能會與直接將其當做純文本替換字符串
- * 返回的結果不一致.如果你需要抑制特殊字符的潛在含義,那麼你可能會需要使用
- * java.util.regex.Matcher類的quoteReplacement方法來實現當前方法的功能。默認情況下,
- * 當前方法是採用java.util.regex.Matcher類的replaceFirst方法實現的.
- *
- * @param regex 給定的正則表達式
- * @param replacement 替換字符串
- * @return String
- * @throws PatternSyntaxException
- * 若給定的正則表達式語法錯誤會拋出此異常
- *
- * @see java.util.regex.Pattern
- *
- * @since 1.4
- * @spec JSR-51
- */
- public String replaceFirst(String regex, String replacement) {
- return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
- }
- /**
- * 根據給定的正則表達式替換當前字符串匹配到的所有子字符串爲參數replacement表示的字符串
- * 注意:replacement參數中若包含反斜槓\和美元符號$可能會與直接將其當做純文本替換字符串
- * 返回的結果不一致.如果你需要抑制特殊字符的潛在含義,那麼你可能會需要使用
- * java.util.regex.Matcher類的quoteReplacement方法來實現當前方法的功能。默認情況下,
- * 當前方法是採用java.util.regex.Matcher類的replaceAll方法實現的.
- *
- * @param regex 給定的正則表達式
- * @param replacement 替換字符串
- * @return String
- * @throws PatternSyntaxException
- * 若給定的正則表達式語法錯誤會拋出此異常
- *
- * @see java.util.regex.Pattern
- *
- * @since 1.4
- * @spec JSR-51
- */
- public String replaceAll(String regex, String replacement) {
- return Pattern.compile(regex).matcher(this).replaceAll(replacement);
- }
- /**
- * 將當前字符串中第一次出現的target字符序列替換爲replacement字符序列
- * 注意:若target或replacement參數中包含了正則表達式中的特殊字符,會一律
- * 按照純文本字符去理解,不會被理解爲它在正則表達式中表達的含義,
- * 即當前方法不支持正則表達式.
- * @param target 被替換的字符序列
- * @param replacement 替換的字符序列
- * @return The resulting string
- * @throws NullPointerException if <code>target</code> or
- * <code>replacement</code> is <code>null</code>.
- * @since 1.5
- */
- public String replace(CharSequence target, CharSequence replacement) {
- return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
- this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
- }
- /**
- * 根據給定的正則表達式來分割當前字符串並返回一個字符串數組
- * 如果給定的正則表達式不匹配當前字符串,那麼返回的字符串數組將只包含一個元素即
- * 當前字符串對象.返回的字符串數組中的每個子字符串與它們在當前字符串中出現的順序
- * 保持一致.
- * limit參數用於控制給定的正則表達式應用的次數,從而影響最終返回的字符串數組的長度.
- * 若limit參數大於零,那麼給定的正則表達式則會至多應用limit - 1次,同時最終返回的
- * 字符串數組的長度將不大於limit,並且該數組的最後一個元素爲前一個子字符串匹配後剩餘
- * 的部分。比如:
- * "Hello world, Java" --> split(" ",2);
- * return: "Hello" "world, Java"
- * 若limit參數是一個負數,那麼給定的正則表達式將會儘可能多的應用多次並且返回的字符串
- * 數組的長度將會沒有限制.
- * 若limit參數爲零,那麼給定的正則表達式將會儘可能多的應用多次並且返回的字符串
- * 數組的長度將會沒有限制,尾部的空字符串將會被丟棄.
- *
- * <p> The string <tt>"boo:and:foo"</tt>, for example, yields the
- * following results with these parameters:
- *
- * <blockquote><table cellpadding=1 cellspacing=0 summary="Split example showing regex, limit, and result">
- * <tr>
- * <th>Regex</th>
- * <th>Limit</th>
- * <th>Result</th>
- * </tr>
- * <tr><td align=center>:</td>
- * <td align=center>2</td>
- * <td><tt>{ "boo", "and:foo" }</tt></td></tr>
- * <tr><td align=center>:</td>
- * <td align=center>5</td>
- * <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
- * <tr><td align=center>:</td>
- * <td align=center>-2</td>
- * <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
- * <tr><td align=center>o</td>
- * <td align=center>5</td>
- * <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr>
- * <tr><td align=center>o</td>
- * <td align=center>-2</td>
- * <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr>
- * <tr><td align=center>o</td>
- * <td align=center>0</td>
- * <td><tt>{ "b", "", ":and:f" }</tt></td></tr>
- * </table></blockquote>
- *
- * <blockquote>
- * {@link java.util.regex.Pattern}.{@link java.util.regex.Pattern#compile
- * compile}<tt>(</tt><i>regex</i><tt>)</tt>.{@link
- * java.util.regex.Pattern#split(java.lang.CharSequence,int)
- * split}<tt>(</tt><i>str</i><tt>,</tt> <i>n</i><tt>)</tt>
- * </blockquote>
- *
- * @param regex 表示分隔符的正則表達式
- * @param limit 限制返回的字符串數組長度的閾值
- * @return 返回當前字符串被分割後生成的字符串數組
- * @throws PatternSyntaxException
- * 若給定的正則表達式語法錯誤會拋出此異常
- *
- * @see java.util.regex.Pattern
- *
- * @since 1.4
- * @spec JSR-51
- */
- public String[] split(String regex, int limit) {
- /**
- * 分3種情況處理:
- * 1. regex參數只有一個字符且該字符串不是正則表達式中的特殊字符 .$|()[{^?*+\ 或者
- * 2. regex參數爲2個字符,第一個字符是一個反斜槓\,第二個字符爲非ASCII碼字母或非ASCII碼數字
- * 3. regex參數超過2個字符並且爲合法的正則表達式
- * 前2種情況採用fastpath方式進行處理,後面第3種情況採用Pattern.split(this, limit)方法實現
- */
- char ch = 0;
- //判定regex參數是否爲上面所描述的前兩種情況
- 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中
- list.add(substring(off, next));
- //修改截取的起始索引位置
- off = next + 1;
- } else {
- //最後一個,只有設置的limit參數大於零,纔會進入這個分支
- list.add(substring(off, value.length));
- off = value.length;
- break;
- }
- }
- // off爲零,當前字符串與給定的regex參數不匹配,那麼直接返回一個字符串數組
- // 並且該字符串數組只包含一個元素且該元素爲當前字符串對象
- if (off == 0)
- return new String[]{this};
- // 添加剩餘的部分
- if (!limited || list.size() < limit) {
- list.add(substring(off, value.length));
- }
- // 構造最終的返回結果
- int resultSize = list.size();
- //若limit參數設置爲零
- if (limit == 0) {
- //從尾部開始遍歷,排除尾部連續的空字符串
- while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
- resultSize--;
- }
- }
- String[] result = new String[resultSize];
- //這裏使用了list.subList方法,而該方法返回的SubList對象會在內部維護當前List對象,
- //對SubList對象中的元素的操作會直接反映到其內部維護的List對象中,若SubList對象沒有
- //被回收,那麼內部維護的List對象也不會被回收,內部維護的List中保存的對象也不會被回收,
- //若內部維護的List是一個超大的集合,那麼就會很容易發生OOM異常
- //應該通過new ArrayList(list.subList(0, resultSize).toArray(result));
- //這種方式來解決這種隱患
- return list.subList(0, resultSize).toArray(result);
- }
- // 若regex參數超過2個字符並且是合法的正則表達式,那麼直接調用Pattern類的.split(this, limit)
- // 來完成實現
- return Pattern.compile(regex).split(this, limit);
- }
- /**
- * split(String regex, int limit)方法的重載,limit參數默認值爲零
- *
- * @since 1.4
- * @spec JSR-51
- */
- public String[] split(String regex) {
- return split(regex, 0);
- }
- /**
- * 使用給定Local的大小寫形式的轉換規則將當前字符串對象的字符序列中包含的每個字符轉換成小寫形式
- * 由於大小寫映射並不總是以1:1的形式進行字符映射,因此可能會導致轉換後的字符串長度與原字符串的長度
- * 不一致.
- *
- * Examples of lowercase mappings are in the following table:
- * <table border="1" summary="Lowercase mapping examples showing language code of locale, upper case, lower case, and description">
- * <tr>
- * <th>Language Code of Locale</th>
- * <th>Upper Case</th>
- * <th>Lower Case</th>
- * <th>Description</th>
- * </tr>
- * <tr>
- * <td>tr (Turkish)</td>
- * <td>\u0130</td>
- * <td>\u0069</td>
- * <td>capital letter I with dot above -> small letter i</td>
- * </tr>
- * <tr>
- * <td>tr (Turkish)</td>
- * <td>\u0049</td>
- * <td>\u0131</td>
- * <td>capital letter I -> small letter dotless i </td>
- * </tr>
- * <tr>
- * <td>(all)</td>
- * <td>French Fries</td>
- * <td>french fries</td>
- * <td>lowercased all chars in String</td>
- * </tr>
- * <tr>
- * <td>(all)</td>
- * <td><img src="doc-files/capiota.gif" alt="capiota"><img src="doc-files/capchi.gif" alt="capchi">
- * <img src="doc-files/captheta.gif" alt="captheta"><img src="doc-files/capupsil.gif" alt="capupsil">
- * <img src="doc-files/capsigma.gif" alt="capsigma"></td>
- * <td><img src="doc-files/iota.gif" alt="iota"><img src="doc-files/chi.gif" alt="chi">
- * <img src="doc-files/theta.gif" alt="theta"><img src="doc-files/upsilon.gif" alt="upsilon">
- * <img src="doc-files/sigma1.gif" alt="sigma"></td>
- * <td>lowercased all chars in String</td>
- * </tr>
- * </table>
- *
- * @param locale 語言環境對象,不同的語言環境下的大小寫字符轉換規則不同
- * @return 返回當前字符串對象的小寫形式
- * @see java.lang.String#toLowerCase()
- * @see java.lang.String#toUpperCase()
- * @see java.lang.String#toUpperCase(Locale)
- * @since 1.1
- */
- public String toLowerCase(Locale locale) {
- //若locale參數爲null,則直接拋出NullPointerException異常
- if (locale == null) {
- throw new NullPointerException();
- }
- int firstUpper;
- final int len = value.length;
- //先掃描出前面本身已經是小寫形式的字符
- scan: {
- for (firstUpper = 0 ; firstUpper < len; ) {
- char c = value[firstUpper];
- //若當前字符在High Surrogate的字符範圍內
- if ((c >= Character.MIN_HIGH_SURROGATE)
- && (c <= Character.MAX_HIGH_SURROGATE)) {
- int supplChar = codePointAt(firstUpper);
- if (supplChar != Character.toLowerCase(supplChar)) {
- break scan;
- }
- //通過Character.charCount計算實際字符的個數
- firstUpper += Character.charCount(supplChar);
- } else {
- if (c != Character.toLowerCase(c)) {
- break scan;
- }
- firstUpper++;
- }
- }
- return this;
- }
- char[] result = new char[len];
- int resultOffset = 0;
- /* 複製第一個小寫字符 */
- System.arraycopy(value, 0, result, 0, firstUpper);
- String lang = locale.getLanguage();
- boolean localeDependent =
- (lang == "tr" || lang == "az" || lang == "lt");
- char[] lowerCharArray;
- int lowerChar;
- int srcChar;
- int srcCount;
- //從firstUpper索引位置開始,後面的字符都是需要進行小寫處理的
- for (int i = firstUpper; i < len; i += srcCount) {
- srcChar = (int)value[i];
- //若當前字符是HIGH SURROGATE
- if ((char)srcChar >= Character.MIN_HIGH_SURROGATE
- && (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
- //獲取實際的Unicode代碼點
- srcChar = codePointAt(i);
- //計算實際字符長度
- srcCount = Character.charCount(srcChar);
- } else {
- srcCount = 1;
- }
- //考慮特殊情況
- if (localeDependent ||
- srcChar == '\u03A3' || // 希臘大寫字母σ
- srcChar == '\u0130') { // 拉丁大寫字母I
- lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale);
- } else {
- //一般情況,直接Character.toLowerCase()方式轉換成小寫
- lowerChar = Character.toLowerCase(srcChar);
- }
- //若轉換後得到的是錯誤字符,或者是一個Unicode補充代碼點
- if ((lowerChar == Character.ERROR)
- || (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
- if (lowerChar == Character.ERROR) {
- lowerCharArray =
- ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale);
- } else if (srcCount == 2) {
- resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount;
- continue;
- } else {
- lowerCharArray = Character.toChars(lowerChar);
- }
- //得到最終小寫字符數組的長度
- int mapLen = lowerCharArray.length;
- //如果大於原字符串長度
- if (mapLen > srcCount) {
- //小寫字符數組擴容
- char[] result2 = new char[result.length + mapLen - srcCount];
- //result --> result2
- System.arraycopy(result, 0, result2, 0, i + resultOffset);
- result = result2;
- }
- for (int x = 0; x < mapLen; ++x) {
- result[i + resultOffset + x] = lowerCharArray[x];
- }
- resultOffset += (mapLen - srcCount);
- } else {
- result[i + resultOffset] = (char)lowerChar;
- }
- }
- return new String(result, 0, len + resultOffset);
- }
- /**
- * toLowerCase(Locale locale)方法的重載,
- * Local默認值爲Locale.getDefault(),默認的Local跟你
- * 當前JVM實例運行的主機系統平臺環境有關
- * @see java.lang.String#toLowerCase(Locale)
- */
- public String toLowerCase() {
- return toLowerCase(Locale.getDefault());
- }
- /**
- * 使用給定Local的大小寫形式的轉換規則將當前字符串對象的字符序列中包含的每個字符轉換成大寫形式
- * 由於大小寫映射並不總是以1:1的形式進行字符映射,因此可能會導致轉換後的字符串長度與原字符串的長度
- * 不一致.
- * @param locale 語言環境對象,不同的語言環境下的大小寫字符轉換規則不同
- * @return 返回當前字符串對象的大寫形式
- * @see java.lang.String#toUpperCase()
- * @see java.lang.String#toLowerCase()
- * @see java.lang.String#toLowerCase(Locale)
- * @since 1.1
- */
- public String toUpperCase(Locale locale) {
- if (locale == null) {
- throw new NullPointerException();
- }
- int firstLower;
- final int len = value.length;
- scan: {
- for (firstLower = 0 ; firstLower < len; ) {
- int c = (int)value[firstLower];
- int srcCount;
- if ((c >= Character.MIN_HIGH_SURROGATE)
- && (c <= Character.MAX_HIGH_SURROGATE)) {
- c = codePointAt(firstLower);
- srcCount = Character.charCount(c);
- } else {
- srcCount = 1;
- }
- int upperCaseChar = Character.toUpperCaseEx(c);
- if ((upperCaseChar == Character.ERROR)
- || (c != upperCaseChar)) {
- break scan;
- }
- firstLower += srcCount;
- }
- return this;
- }
- char[] result = new char[len]; /* may grow */
- int resultOffset = 0; /* result may grow, so i+resultOffset
- * is the write location in result */
- /* Just copy the first few upperCase characters. */
- System.arraycopy(value, 0, result, 0, firstLower);
- String lang = locale.getLanguage();
- boolean localeDependent =
- (lang == "tr" || lang == "az" || lang == "lt");
- char[] upperCharArray;
- int upperChar;
- int srcChar;
- int srcCount;
- for (int i = firstLower; i < len; i += srcCount) {
- srcChar = (int)value[i];
- if ((char)srcChar >= Character.MIN_HIGH_SURROGATE &&
- (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
- srcChar = codePointAt(i);
- srcCount = Character.charCount(srcChar);
- } else {
- srcCount = 1;
- }
- if (localeDependent) {
- upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale);
- } else {
- upperChar = Character.toUpperCaseEx(srcChar);
- }
- if ((upperChar == Character.ERROR)
- || (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
- if (upperChar == Character.ERROR) {
- if (localeDependent) {
- upperCharArray =
- ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale);
- } else {
- upperCharArray = Character.toUpperCaseCharArray(srcChar);
- }
- } else if (srcCount == 2) {
- resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount;
- continue;
- } else {
- upperCharArray = Character.toChars(upperChar);
- }
- /* Grow result if needed */
- int mapLen = upperCharArray.length;
- if (mapLen > srcCount) {
- char[] result2 = new char[result.length + mapLen - srcCount];
- System.arraycopy(result, 0, result2, 0, i + resultOffset);
- result = result2;
- }
- for (int x = 0; x < mapLen; ++x) {
- result[i + resultOffset + x] = upperCharArray[x];
- }
- resultOffset += (mapLen - srcCount);
- } else {
- result[i + resultOffset] = (char)upperChar;
- }
- }
- return new String(result, 0, len + resultOffset);
- }
- /**
- * toUpperCase(Locale locale)方法的重載,Local參數默認值爲Locale.getDefault(),
- * 默認的Local跟你當前JVM實例運行的主機系統平臺環境有關
- * @see java.lang.String#toUpperCase(Locale)
- */
- public String toUpperCase() {
- return toUpperCase(Locale.getDefault());
- }
- /**
- * 剔除掉當前字符串對象的兩頭連續的空格字符,並返回一個新的字符串對象
- *
- * @return 返回剔除掉兩頭空格後的字符串對象
- */
- public String trim() {
- int len = value.length;
- int st = 0;
- char[] val = value;
- //從開頭開始找空格字符
- while ((st < len) && (val[st] <= ' ')) {
- st++;
- }
- //從末尾往開頭找空格字符
- while ((st < len) && (val[len - 1] <= ' ')) {
- len--;
- }
- //若沒找到空格字符,則直接返回當前字符串對象,否則截取字符串並返回
- return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
- }
- /**
- * 因爲當前字符串對象已經是String類型,因此這裏直接return this.
- *
- * @return the string itself.
- */
- public String toString() {
- return this;
- }
- /**
- * 將當前字符串對象轉換成一個字符數組
- *
- * @return 返回當前字符串對象轉換後得到的一個字符數組,該字符數組的長度與
- * 當前字符串的長度一致
- */
- public char[] toCharArray() {
- // 由於類初始化問題,這裏不能使用Arrays.copyOf()方法來實現
- char result[] = new char[value.length];
- System.arraycopy(value, 0, result, 0, value.length);
- return result;
- }
- /**
- * 使用指定的字符串格式和參數返回一個格式化後的字符串
- *
- * @param format 字符串格式參數
- *
- * @param args 字符串格式中需要替換的參數
- *
- * //@throws IllegalFormatException
- * 如果給定的字符串格式不合法或者給定的字符串格式與指定的參數不兼容,
- * 或者給定的字符串格式需要的參數個數大於實際指定的參數個數,則會拋出
- * IllegalFormatException異常
- *
- * @throws NullPointerException
- * 如果format參數等於null,則會拋出NullPointerException異常
- *
- * @return 返回格式化後的字符串
- *
- * @see java.util.Formatter
- * @since 1.5
- */
- public static String format(String format, Object... args) {
- return new Formatter().format(format, args).toString();
- }
- /**
- * 使用指定的字符串格式和參數在指定的語言環境下返回一個格式化後的字符串
- *
- * @param l 本地語言環境
- * @param format 字符串格式
- * @param args 字符串格式中需要替換的參數
- *
- * //@throws IllegalFormatException
- * 如果給定的字符串格式不合法或者給定的字符串格式與指定的參數不兼容,
- * 或者給定的字符串格式需要的參數個數大於實際指定的參數個數,則會拋出
- * IllegalFormatException異常
- *
- * @throws NullPointerException
- * 如果format參數等於null,則會拋出NullPointerException異常
- *
- * @return 返回格式化後的字符串
- *
- * @see java.util.Formatter
- * @since 1.5
- */
- public static String format(Locale l, String format, Object... args) {
- return new Formatter(l).format(format, args).toString();
- }
- /**
- * 將指定的obj對象轉換成String對象
- *
- * @param obj 任意的Object對象
- * @return 若obj == null,則會返回字符串"null",否則返回obj.toString()
- * @see java.lang.Object#toString()
- */
- public static String valueOf(Object obj) {
- return (obj == null) ? "null" : obj.toString();
- }
- /**
- * 將指定的字符數組對象轉換成String對象
- *
- * @param data 字符數組對象
- * @return 返回一個新的字符串對象
- */
- public static String valueOf(char data[]) {
- return new String(data);
- }
- /**
- * 將指定的字符數組的[offset,offset + count]區間內的字符序列轉換成一個字符串對象
- *
- * @param data 字符數組
- * @param offset 截取的起始偏移量
- * @param count 截取的字符個數
- * @return 返回一個包含給定字符數組指定區間內的字符序列的字符串對象
- * @exception IndexOutOfBoundsException
- * 若offset爲負數或
- * count爲負數或
- * offset + count > data.length(),
- * 則會拋出IndexOutOfBoundsException數組索引位置越界異常
- */
- public static String valueOf(char data[], int offset, int count) {
- return new String(data, offset, count);
- }
- /**
- * 將指定的字符數組的[offset,offset + count]區間內的字符序列轉換成一個字符串對象
- * 同valueOf(char data[], int offset, int count)方法實現細節一模一樣,僅僅只是方法名稱不同
- */
- public static String copyValueOf(char data[], int offset, int count) {
- return new String(data, offset, count);
- }
- /**
- * 將指定的字符數組轉換成一個字符串對象
- * 同valueOf(char data[])方法的具體實現細節一模一樣,僅僅只是方法名稱不同
- *
- * @param data 字符數組對象
- * @return 返回一個新的字符串對象
- */
- public static String copyValueOf(char data[]) {
- return new String(data);
- }
- /**
- * 將boolean變量值轉換成一個字符串對象
- *
- * @param b 一個boolean值
- * @return true --> "true"
- * false --> "false"
- */
- public static String valueOf(boolean b) {
- return b ? "true" : "false";
- }
- /**
- * 將單個字符轉換成一個字符串對象
- *
- * @param c 一個字符
- * @return 返回單個字符轉換後得到的一個長度爲1的字符串對象
- */
- public static String valueOf(char c) {
- char data[] = {c};
- return new String(data, true);
- }
- /**
- * 將int數字轉換成一個字符串對象
- * 內部實際是調用Integer.toString()方法實現的
- *
- * @param i int數字
- * @return 返回一個int類型的數字的字符串表示形式
- * @see java.lang.Integer#toString(int, int)
- */
- public static String valueOf(int i) {
- return Integer.toString(i);
- }
- /**
- * 將long數字轉換成一個字符串對象
- * 內部實際是調用Long.toString()方法實現的
- *
- * @param l long類型的數字
- * @return 返回一個long類型的數字的字符串表示形式
- * @see java.lang.Long#toString(long)
- */
- public static String valueOf(long l) {
- return Long.toString(l);
- }
- /**
- * 將float數字轉換成一個字符串對象
- * 內部實際是調用Float.toString()方法實現的
- *
- * @param f float類型的數字
- * @return 返回一個float類型的數字的字符串表示形式
- * @see java.lang.Float#toString(float)
- */
- public static String valueOf(float f) {
- return Float.toString(f);
- }
- /**
- * 將double數字轉換成一個字符串對象
- * 內部實際是調用Double.toString()方法實現的
- *
- * @param d double類型的數字
- * @return 返回一個double類型的數字的字符串表示形式
- * @see java.lang.Double#toString(double)
- */
- public static String valueOf(double d) {
- return Double.toString(d);
- }
- /**
- * 返回字符串對象的規範化表示形式
- * 字符串常量池初始化默認是空的,它由String類私下管理維護
- * 當intern方法被執行,如果字符串常量池已經包含了與當前字符串對象equals的字符串,
- * 那麼直接從字符串常量池裏返回該字符串對象即可,否則會將該字符串對象添加到常量池中
- * 並返回.
- * 因此對於任意的兩個字符串s和t,
- * 當且僅當s.equals(t) == true,
- * s.intern() == t.intern()纔會返回true.
- * 所有的字符串字面量以及基於String的常量表達式都會被字符串常量池集中管理和返回.
- *
- * @return 從字符串常量池返回一個字符串,保持返回的字符串是在常量池中並且是唯一的
- */
- public native String intern();
- /** Hash計算需要的種子 */
- private static final int HASHING_SEED;
- static {
- //當前的納秒數
- long nanos = System.nanoTime();
- //當前的毫秒數
- long now = System.currentTimeMillis();
- //Hash種子利用了String類和System類的加載路徑以及當前系統時間的納秒數、毫秒數
- int SEED_MATERIAL[] = {
- System.identityHashCode(String.class),
- System.identityHashCode(System.class),
- (int) (nanos >>> 32),
- (int) nanos,
- (int) (now >>> 32),
- (int) now,
- (int) (System.nanoTime() >>> 2)
- };
- // 內部實現避免加載類
- int h1 = 0;
- // Hash種子計算的核心部分
- for (int k1 : SEED_MATERIAL) {
- k1 *= 0xcc9e2d51;
- k1 = (k1 << 15) | (k1 >>> 17);
- k1 *= 0x1b873593;
- h1 ^= k1;
- h1 = (h1 << 13) | (h1 >>> 19);
- h1 = h1 * 5 + 0xe6546b64;
- }
- // tail (always empty, as body is always 32-bit chunks)
- // finalization
- h1 ^= SEED_MATERIAL.length * 4;
- // finalization mix force all bits of a hash block to avalanche
- h1 ^= h1 >>> 16;
- h1 *= 0x85ebca6b;
- h1 ^= h1 >>> 13;
- h1 *= 0xc2b2ae35;
- h1 ^= h1 >>> 16;
- HASHING_SEED = h1;
- }
- /** 存儲另一種Hash散列算法的計算結果,因爲int佔4個字節共32個bit,因此這裏得到的是32位的Hash值 */
- private transient int hash32 = 0;
- /**
- * 針對當前字符串對象計算得到一個32位的Hash值
- *
- * @return a 返回一個32位的Hash值
- */
- int hash32() {
- int h = hash32;
- if (0 == h) {
- // Murmur3 hashing函數針對碰撞攻擊提供了優秀的保護機制
- h = sun.misc.Hashing.murmur3_32(HASHING_SEED, value, 0, value.length);
- // 確保最終計算的Hash值不爲零,如果計算後得到爲零,
- // 強制賦值爲1,以避免重複進行Hash計算
- h = (0 != h) ? h : 1;
- hash32 = h;
- }
- return h;
- }
- }
String源碼詳解
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.