中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

String、StringBuffer和StringBuilder的使用方法

發布時間:2020-06-12 15:38:00 來源:億速云 閱讀:207 作者:元一 欄目:編程語言

  前言

  相信很多程序員在使用String、StringBuilder和StringBuffer的時候都知道怎么使用,卻并不會去看其原理,

  在學習這三個類之前先認識一下CharSequence接口和Appendable接口:

  CharSequence接口,出自于JDK1.4,有如下幾個常用的方法:

  int length(); 返回字符序列長度

  char charAt(int index); 返回字符序列在指定索引處的字符

  CharSequence subSequence(int start, int end); 截取字符序列從索引start到end之間的值。包括start不包括end。例如:長度為5的字符序列“12345”,截圖0到3的值為“123”,即真正的返回值為索引start到end-1之間的值。

  Appendable接口,出自JDK1.5,有如下幾個常用方法:

  Appendable append(CharSequence csq) throws IOException; 拼接字符序列

  Appendable append(CharSequence csq, int start, int end) throws IOException; 拼接字符序列指定區間內的字符序列,包括start不包括end。即真正拼接的值為索引start到end-1之間的值。

  Appendable append(char c) throws IOException; 拼接字符

  概括

  String類是字符串常量,是不可更改的常量。而StringBuffer是字符串變量,它的對象是可以擴充和修改的。

  StringBuffer類的構造函數

  public StringBuffer()

  創建一個空的StringBuffer類的對象。

  public StringBuffer( int length )

  創建一個長度為 參數length 的StringBuffer類的對象。

  注意:如果參數length小于0,將觸發NegativeArraySizeException異常。

  public StringBuffer( String str )

  用一個已存在的字符串常量來創建StringBuffer類的對象。

  StringBuffer類

  StringBuffer類,繼承AbstractStringBuilder,實現Serializable序列化,操作上是線程安全的,線程安全的原因就是該類進行數據操作的相關方法都加了synchronized關鍵字,而StringBuilder則都沒有加。

  toStringCache變量:使用transient修飾,不參與序列化,作為toString方法緩存用

  默認構造器:調用父類構造器,傳遞一個默認的長度值16,父類構造器創建一個長度為16的字符數組;

  參數為int的構造器:參數為int的構造器意思是構造一個指定長度的字符數組

  參數為String和CharSequence的構造器:會構造一個長度為(16+CharSequence字符長度)或者(16+String字符串長度)的字符數組。然后再拼接一下參數中的字符或者字符串,如果參數為null會拋出空指針異常(NullPointerException)。

  length方法:返回實際數據長度

  capacity方法:返回父類構造器的字符數組長度

  public final class StringBuffer extends AbstractStringBuilder

  implements java.io.Serializable, CharSequence{

  private transient char[] toStringCache;

  /** use serialVersionUID from JDK 1.0.2 for interoperability */

  static final long serialVersionUID = 3388685877147921107L;

  public StringBuffer() {

  super(16);

  }

  public StringBuffer(int capacity) {

  super(capacity);

  }

  public StringBuffer(String str) {

  super(str.length() + 16);

  append(str);

  }

  public StringBuffer(CharSequence seq) {

  this(seq.length() + 16);

  append(seq);

  }

  @Override

  public synchronized int length() {

  return count;

  }

  @Override

  public synchronized int capacity() {

  return value.length;

  }

  接下來看一看一些相關操作的方法:

  可以看到如拼接,插入,刪除,替換之類的操作都是調用父類的方法,并且返回的是調用該方法的類對象,這就表明StringBuffer類在進行數據改變的操作后返回類對象本身,原因就是父類中儲存數據的字符數組value沒有final所修飾,所以可以做到修改數據而不改變類對象。

  而String類中儲存數據的字符數組變量value是被final修飾的,也就說明無法對String類對象的值進行直接的修改,所以對其進行數據改變操作的返回值都是new String(XXX),也就是每個返回值都是一個新的String對象,所以String類不適合大量的數據值改變的操作。

  toStringCache變量:只有在調用toString方法的時候給予賦值操作,臨時儲存數據,然后轉換為Sting對象當做返回值。而每次對數據進行改變的時候都會重置變量值,保證每次toString之前該變量都是空。

  @Override

  public synchronized StringBuffer append(String str) {

  toStringCache = null;

  super.append(str);

  return this;

  }

  @Override

  public synchronized StringBuffer delete(int start, int end) {

  toStringCache = null;

  super.delete(start, end);

  return this;

  }

  @Override

  public synchronized StringBuffer replace(int start, int end, String str) {

  toStringCache = null;

  super.replace(start, end, str);

  return this;

  }

  @Override

  public synchronized StringBuffer insert(int index, char[] str, int offset,

  int len)

  {

  toStringCache = null;

  super.insert(index, str, offset, len);

  return this;

  }

  @Override

  public int indexOf(String str) {

  // Note, synchronization achieved via invocations of other StringBuffer methods

  return super.indexOf(str);

  }

  @Override

  public synchronized int indexOf(String str, int fromIndex) {

  return super.indexOf(str, fromIndex);

  }

  @Override

  public int lastIndexOf(String str) {

  // Note, synchronization achieved via invocations of other StringBuffer methods

  return lastIndexOf(str, count);

  }

  @Override

  public synchronized int lastIndexOf(String str, int fromIndex) {

  return super.lastIndexOf(str, fromIndex);

  }

  @Override

  public synchronized StringBuffer reverse() {

  toStringCache = null;

  super.reverse();

  return this;

  }

  @Override

  public synchronized String toString() {

  if (toStringCache == null) {

  toStringCache = Arrays.copyOfRange(value, 0, count);

  }

  return new String(toStringCache, true);

  }

  StringBuilder類

  StringBuilder類和StringBuffer差不多,少了一個toStringCache變量,所以的操作方法都沒有添加sybchronized關鍵字,所以StringBuilder是線程不安全的類。就不多說了哈(*^▽^*)。

  AbstractStringBuilder

  AbstractStringBuilder產于JDK1.5,實現Appendable接口和CharSequence接口

  該類只能被繼承,有兩個子類StringBuffer和StringBuilder,會默認調用有參構造器,指定初始化的字符串數據長度

  value: 實例化時創建出來的字符數組

  count: 實際數據包含的字符的長度

  length方法:返回實際數據包含的字符的長度

  capacity方法:返回字符數組的大小

  代碼如下:

  abstract class AbstractStringBuilder implements Appendable, CharSequence {

  char[] value;

  int count;

  AbstractStringBuilder() {

  }

  AbstractStringBuilder(int capacity) {

  value = new char[capacity];

  }

  @Override

  public int length() {

  return count;

  }

  public int capacity() {

  return value.length;

  }

  數據儲存空間操作相關方法:

  ensureCapacityInternal:每次進行數據改變操作之前都會調用的方法,其意在于確保數組變量value有能力承受接下來的改變,說白了就是對數據操作的之前改變字符數組大小,使其容量能足夠接下來的操作使用而不出現錯誤。

  MAX_ARRAY_SIZE:私有靜態常量,值為 Integer.MAX_VALUE - 8,按照文檔翻譯來說,就是字符數組的最大容量,但是卻沒有達到Integer的最大值,原因是某些JVM虛擬機會在一個數組中保留一些標題詞,如果強行嘗試區分配超過這個容量的數組可能會導致拋出異常OutOfMemoryError:請求的數組大小超過VM限制。

  newCapacity:重新設置字符數組的容量,并作為返回值。參數表示字符數組的最小容量,首先要知道字符串數組初始長度為16,擴容方式為原字符數組長度左移一位后再加2(原字符數組長度乘以2,再加2)。該方法就是比較一次擴容后value長度值newCapacity和參數指定的最小值minCapacity,如果一次擴容滿足最小值需求,則使用newCapacity,如果不滿于則直接使用minCapacity并且賦值于newCapacity,最后判斷minCapacity的大小是否大于0并小于指定的MAX_ARRAY_SIZE的值,如果滿足則返回minCapacity的值,如果不滿足則表示要求的最小值超過了建議的最大值容量,那將把minCapacity傳遞給為hugeCapacity方法,并以該方法的返回值作為本方法的返回值,如下。鄭州專業婦科醫院 http://www.hnzzkd.com/

  hugeCapacity:如果參數給定值超過Integer的類型最大值,拋出內存溢出異常,如果小于Integer的最大值,則和AbstractStringBuilder類的建議值對比,哪一個值大,則使用哪一個值作為返回值。

  trimToSize:去除多余的數組儲存空間,提高空間利用率。比較數組空間value的大小和實際數據count大小,如果實際數據元素小于value,則表示實際數據并未占滿分配的空間,調用Arrays.copyOf方法把value中的空間鋪滿,返回鋪滿后的value值,

  setLength:設置當前序列的長度為指定的參數長度newLength,如果當前序列的長度超出指定長度newLength,就把已有序列的前面長度為newLength的字符拷貝到新字符序列里,多出來的一部分舍棄。如果不超過newLegth,原有數據不變,就把缺少的幾個位置的數據設置為空字符。

  private void ensureCapacityInternal(int minimumCapacity) {

  // overflow-conscious code

  if (minimumCapacity - value.length > 0) {

  value = Arrays.copyOf(value,

  newCapacity(minimumCapacity));

  }

  }

  private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

  private int newCapacity(int minCapacity) {

  // overflow-conscious code

  int newCapacity = (value.length << 1) + 2;

  if (newCapacity - minCapacity < 0) {

  newCapacity = minCapacity;

  }

  return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)

  ? hugeCapacity(minCapacity)

  : newCapacity;

  }

  private int hugeCapacity(int minCapacity) {

  if (Integer.MAX_VALUE - minCapacity < 0) { // overflow

  throw new OutOfMemoryError();

  }

  return (minCapacity > MAX_ARRAY_SIZE)

  ? minCapacity : MAX_ARRAY_SIZE;

  }

  public void trimToSize() {

  if (count < value.length) {

  value = Arrays.copyOf(value, count);

  }

  }

  public void setLength(int newLength) {

  if (newLength < 0)

  throw new StringIndexOutOfBoundsException(newLength);

  ensureCapacityInternal(newLength);

  if (count < newLength) {

  Arrays.fill(value, count, newLength, '\0');

  }

  count = newLength;

  }

  接下來看一下實際的數據操作,這里以最常用的拼接和替換為例:

  appendNull:先擴容,然后依次拼接字符n u l l,拼接的同時進行count++;

  append:先判斷字符串是否為null,如果是執行appendNull,如果不是空,則獲取目標對象的長度,然后進行擴容,然后把目標對象拷貝到value的后面。然后更新數據的大小count。返回類對象

  replace:先判斷一系列索引越界問題,如果都沒問題檢查end是否超出count,超出了則修改end的值為count,獲取目標字符串的長度,計算經過替換后的數據長度。原長度減去要被替換的長度加上要替換成的字符串長度:count-(end-start)+len。計算完成后更新字符數組大小,拷貝字符后更新count的值。返回類對象

  private AbstractStringBuilder appendNull() {

  int c = count;

  ensureCapacityInternal(c + 4);

  final char[] value = this.value;

  value[c++] = 'n';

  value[c++] = 'u';

  value[c++] = 'l';

  value[c++] = 'l';

  count = c;

  return this;

  }

  public AbstractStringBuilder append(String str) {

  if (str == null)

  return appendNull();

  int len = str.length();

  ensureCapacityInternal(count + len);

  str.getChars(0, len, value, count);

  count += len;

  return this;

  }

  public AbstractStringBuilder replace(int start, int end, String str) {

  if (start < 0)

  throw new StringIndexOutOfBoundsException(start);

  if (start > count)

  throw new StringIndexOutOfBoundsException("start > length()");

  if (start > end)

  throw new StringIndexOutOfBoundsException("start > end");

  if (end > count)

  end = count;

  int len = str.length();

  int newCount = count + len - (end - start);

  ensureCapacityInternal(newCount);

  System.arraycopy(value, end, value, start + len, count - end);

  str.getChars(value, start);

  count = newCount;

  return this;

  }

  public AbstractStringBuilder delete(int start, int end) {

  if (start < 0)

  throw new StringIndexOutOfBoundsException(start);

  if (end > count)

  end = count;

  if (start > end)

  throw new StringIndexOutOfBoundsException();

  int len = end - start;

  if (len > 0) {

  System.arraycopy(value, start+len, value, start, count-end);

  count -= len;

  }

  return this;

  }

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

富源县| 建平县| 民和| 固始县| 汝州市| 会昌县| 三门县| 正定县| 远安县| 麻阳| 广水市| 石嘴山市| 钟祥市| 大邑县| 交口县| 开化县| 四川省| 仲巴县| 同仁县| 安泽县| 四平市| 鹿泉市| 鄂伦春自治旗| 宜昌市| 宁远县| 余干县| 潮安县| 禹城市| 尚志市| 玛曲县| 毕节市| 应城市| 奇台县| 菏泽市| 井陉县| 邛崃市| 农安县| 江门市| 延边| 淄博市| 腾冲县|