最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JDK源碼分析之String、StringBuilder和StringBuffer

 更新時(shí)間:2018年05月21日 09:22:24   投稿:daisy  
這篇文章主要給大家介紹了關(guān)于JDK源碼分析之String、StringBuilder和StringBuffer的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用jdk具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

本文主要介紹了關(guān)于JDK源碼分析之String、StringBuilder和StringBuffer的相關(guān)內(nèi)容,分享出來(lái)供大家參考學(xué)習(xí),下面話(huà)不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧

String類(lèi)的申明

public final class String
 implements java.io.Serializable, Comparable<String>, CharSequence {…}

String類(lèi)用了final修飾符,表示它不可以被繼承,同時(shí)還實(shí)現(xiàn)了三個(gè)接口, 實(shí)現(xiàn)Serializable接口表示String類(lèi)可被序列化;實(shí)現(xiàn)Comparable<T> 接口主要是提供一個(gè)compareTo 方法用于比較String字符串;還實(shí)現(xiàn)了CharSequence 接口,這個(gè)接口代表的是char值得一個(gè)可讀序列(CharBuffer, Segment, String, StringBuffer, StringBuilder也都實(shí)現(xiàn)了CharSequence接口)

String主要字段、屬性說(shuō)明

/*字符數(shù)組value,存儲(chǔ)String中實(shí)際字符 */
private final char value[];
/*字符串的哈希值 默認(rèn)值0*/
private int hash; 
/*字符串的哈希值 默認(rèn)值0*/
/*一個(gè)比較器,用來(lái)排序String對(duì)象, compareToIgnoreCase方法中有使用 */
public static final Comparator<String> CASE_INSENSITIVE_ORDER
      = new CaseInsensitiveComparator();

String 部分方法分析

String類(lèi)提供了系列的構(gòu)造函數(shù),其中有幾個(gè)都已經(jīng)不推薦使用了,如下圖:

構(gòu)造函數(shù)

以下是兩個(gè)常用的構(gòu)造函數(shù)的實(shí)現(xiàn):

//String str = new String(“123”)
public String(String original) {
  this.value = original.value;
  this.hash = original.hash;
}

//String str3 = new String(new char[] {'1','2','3'});
public String(char value[]) {
   //將字符數(shù)組值copy至value
  this.value = Arrays.copyOf(value, value.length); 
 }

boolean equals(Object anObject)

 String 類(lèi)重寫(xiě)了 equals 方法,將此字符串與指定的對(duì)象比較。當(dāng)且僅當(dāng)該參數(shù)不為 null,并且是與此對(duì)象表示相同字符序列的 String 對(duì)象時(shí),結(jié)果才為 true。

public boolean equals(Object anObject) {
  //直接將對(duì)象引用相比較,相同返回true
  if (this == anObject) {
   return true;
  }
  //比較當(dāng)前對(duì)象與anObject的字符序列value
  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;
 }

int compareTo(String anotherString)

 逐位比較兩個(gè)字符串的字符序列,如果某一位字符不相同,則返回該位的兩個(gè)字符的Unicode 值的差,所有位都相同,則計(jì)算兩個(gè)字符串長(zhǎng)度之差,兩個(gè)字符串相同則返回0

public int compareTo(String anotherString) {
  int len1 = value.length;
  int len2 = anotherString.value.length;
  //取長(zhǎng)度較小的字符串的長(zhǎng)度
  int lim = Math.min(len1, len2);
  char v1[] = value;
  char v2[] = anotherString.value;

  int k = 0;
  while (k < lim) {
   //將兩個(gè)字符串的字符序列value逐個(gè)比較,如果不等,則返回該位置兩個(gè)字符的Unicode 之差
   char c1 = v1[k];
   char c2 = v2[k];
   if (c1 != c2) {
    return c1 - c2; //返回Unicode 之差

   }
   k++;
  }
  //長(zhǎng)度較小的字符串所有位都比較完,則返回兩個(gè)字符串長(zhǎng)度之差
  //如果兩個(gè)字符串相同,那么長(zhǎng)度之差為0,即相同字符串返回0
  return len1 - len2;
 }

compareToIgnoreCase(String str)方法實(shí)現(xiàn)于此類(lèi)似,比較時(shí)忽略字符的大小寫(xiě),實(shí)現(xiàn)方式如下:

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) {
       // No overflow because of numeric promotion
       return c1 - c2;
      }
     }
    }
   }
   return n1 - n2;
  }

native String intern()

當(dāng)調(diào)用 intern 方法時(shí),如果池已經(jīng)包含一個(gè)等于此 String 對(duì)象的字符串(用 equals(Object) 方法確定),則返回池中的字符串。否則,將此 String 對(duì)象添加到池中,并返回此 String 對(duì)象的引用。

所有字面值字符串和字符串賦值常量表達(dá)式都使用 intern 方法進(jìn)行操作,例如:String str1 = "123";

String內(nèi)存位置:常量池OR堆

String對(duì)象可以直接通過(guò)字面量創(chuàng)建,也可以通過(guò)構(gòu)造函數(shù)創(chuàng)建,有什么區(qū)別呢?

 1.通過(guò)字面量或者字面量字符串通過(guò)”+”拼接的方式創(chuàng)建的String對(duì)象存儲(chǔ)在常量池中,實(shí)際創(chuàng)建時(shí)如果常量池中存在,則直接返回引用,如果不存在則創(chuàng)建該字符串對(duì)象

 2.使用構(gòu)造函數(shù)創(chuàng)建字符串對(duì)象,則直接在堆中創(chuàng)建一個(gè)String對(duì)象

 3.調(diào)用intern方法,返回則會(huì)將該對(duì)象放入常量池(不存在則放入常量池,存在則返回引用)

下面舉例說(shuō)明String對(duì)象內(nèi)存分配情況:

String str1 = new String("123");
  String str2 = "123";
  String str3 = "123";
  String str4 = str1.intern();
  System.out.println(str1==str2); // false str1在堆中創(chuàng)建對(duì)象,str2在常量池中創(chuàng)建對(duì)象
  System.out.println(str2==str3); // true str2在常量池中創(chuàng)建對(duì)象,str3直接返回的str2創(chuàng)建的對(duì)象的引用 所以str2和str3指向常量池中同一個(gè)對(duì)象
  System.out.println(str4==str3); // true str4返回常量池中值為"123"的對(duì)象,因此str4和str2、str3都相等


關(guān)于字符串拼接示例:

public class StringTest {
 public static final String X = "ABC"; // 常量X
 @Test
 public void Test() {

  String str5 = new String("ABC");
  String str6 = str5+"DEF"; //堆中創(chuàng)建
  String str7 = "ABC"+"DEF"; //常量池
  String str8 = X+"DEF";  //X為常量,值是固定的,因此X+"DEF"值已經(jīng)定下來(lái)為ABCDEF,實(shí)際上編譯后得代碼相當(dāng)于String str8 = "ABCDEF"
  String str9 = "ABC";  
  String str10 = str9+"DEF"; //堆中
  
  System.out.println(str6==str7); //false
  System.out.println(str8==str7); //true
  System.out.println(str10==str7); //false

  System.out.println(X==str9); //true
} }

反編譯后的代碼看一下便一目了然:

 

內(nèi)存分配如下:

 

String、StringBuffer、StringBuilder

 由于String類(lèi)型內(nèi)部維護(hù)的用于存儲(chǔ)字符串的屬性value[]字符數(shù)組是用final來(lái)修飾的:

/** The value is used for character storage. */
private final char value[];

表明在賦值后可以再修改,因此我們認(rèn)為String對(duì)象一經(jīng)創(chuàng)建后不可變,在開(kāi)發(fā)過(guò)程中如果碰到頻繁的拼接字符串操作,如果使用String提供的contact或者直接使用”+”拼接字符串會(huì)頻繁的生成新的字符串,這樣使用顯得低效。Java提供了另外兩個(gè)類(lèi):StringBuffer和StringBuilder,用于解決這個(gè)問(wèn)題:

看一下下面的代碼:

String str1="123";
   String str2="456";
   String str3="789";   
   String str4 = "123" + "456" + "789"; //常量相加,編譯器自動(dòng)識(shí)別 String str4=“123456789”   
   String str5 = str1 + str2 + str3; //字符串變量拼接,推薦使用StringBuilder   
   StringBuilder sb = new StringBuilder(); 
   sb.append(str1);
   sb.append(str2);
   sb.append(str3);

下面是StringBuilder類(lèi)的實(shí)現(xiàn),只截取了分析的部分代碼:

public final class StringBuilder
 extends AbstractStringBuilder
 implements java.io.Serializable, CharSequence
{

 //拼接字符串
 @Override
 public StringBuilder append(String str) {
 //調(diào)用父類(lèi)AbstractStringBuilder.append super.append(str); return this; } }
abstract class AbstractStringBuilder implements Appendable, CharSequence {
 /**
  * 存儲(chǔ)字符串的字符數(shù)組,非final類(lèi)型,區(qū)別于String類(lèi)
  */
 char[] value;

 /**
  * The count is the number of characters used.
  */
 int count;

 public AbstractStringBuilder append(String str) {
  if (str == null)
   return appendNull();
  int len = str.length();
   //檢查是否需要擴(kuò)容
  ensureCapacityInternal(count + len);
  //字符串str拷貝至value  
  str.getChars(0, len, value, count);
  count += len;
  return this;
}


 private void ensureCapacityInternal(int minimumCapacity) {
  // overflow-conscious code
  // minimumCapacity=count+str.length
  //拼接上str后的容量 如果 大于value容量,則擴(kuò)容
  if (minimumCapacity - value.length > 0) {
    
    //擴(kuò)容,并將當(dāng)前value值拷貝至擴(kuò)容后的字符數(shù)組,返回新數(shù)組引用
   value = Arrays.copyOf(value,
     newCapacity(minimumCapacity));
  }
 }

 //StringBuilder擴(kuò)容
 private int newCapacity(int minCapacity) {
  // overflow-conscious code
  // 計(jì)算擴(kuò)容容量
  // 默認(rèn)擴(kuò)容后的數(shù)組長(zhǎng)度是按原數(shù)(value[])組長(zhǎng)度的2倍再加上2的規(guī)則來(lái)擴(kuò)展,為什么加2?
  int newCapacity = (value.length << 1) + 2;
  if (newCapacity - minCapacity < 0) {
   newCapacity = minCapacity;
  }
  return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
   ? hugeCapacity(minCapacity)
   : newCapacity;
 }
}

StringBuffer和StringBuilder用一樣,內(nèi)部維護(hù)的value[]字符數(shù)組都是可變的,區(qū)別只是StringBuffer是線(xiàn)程安全的,它對(duì)所有方法都做了同步,StringBuilder是線(xiàn)程非安全的,因此在多線(xiàn)程操作共享字符串變量的情況下字符串拼接處理首選用StringBuffer, 否則可以使用StringBuilder,畢竟線(xiàn)程同步也會(huì)帶來(lái)一定的消耗。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Maven使用集成測(cè)試的示例代碼

    Maven使用集成測(cè)試的示例代碼

    本文介紹了在Maven項(xiàng)目中使用maven-failsafe-plugin插件進(jìn)行集成測(cè)試,步驟包括添加測(cè)試依賴(lài)、編寫(xiě)集成測(cè)試類(lèi)、配置插件、運(yùn)行測(cè)試以及查看和分析測(cè)試結(jié)果,感興趣的可以了解一下
    2024-11-11
  • springboot后端解決跨域問(wèn)題

    springboot后端解決跨域問(wèn)題

    今天小編就為大家分享一篇關(guān)于springboot后端解決跨域問(wèn)題,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-03-03
  • 一文詳解Java的餓漢和懶漢設(shè)計(jì)模式

    一文詳解Java的餓漢和懶漢設(shè)計(jì)模式

    這篇文章主要為大家詳細(xì)介紹了Java設(shè)計(jì)模式中的的餓漢模式和懶漢模式,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定的幫助,需要的可以參考一下
    2022-12-12
  • java實(shí)現(xiàn)的冒泡排序算法示例

    java實(shí)現(xiàn)的冒泡排序算法示例

    這篇文章主要介紹了java實(shí)現(xiàn)的冒泡排序算法,結(jié)合實(shí)例形式分析了冒泡排序算法的具體操作步驟與實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-01-01
  • mybatisPlus中apply的使用以進(jìn)行聯(lián)表等復(fù)雜sql語(yǔ)句詳解

    mybatisPlus中apply的使用以進(jìn)行聯(lián)表等復(fù)雜sql語(yǔ)句詳解

    在MyBatis-Plus中,`apply()`方法可以用于添加任意的SQL片段,包括聯(lián)表查詢(xún),使用`apply()`方法的好處是可以直接添加原生的SQL片段,而不受MyBatis-Plus提供的常規(guī)查詢(xún)條件構(gòu)建方法的限制,但是,使用`apply()`方法需要注意安全性和性能問(wèn)題
    2025-03-03
  • 基于SPRINGBOOT配置文件占位符過(guò)程解析

    基于SPRINGBOOT配置文件占位符過(guò)程解析

    這篇文章主要介紹了基于SPRINGBOOT配置文件占位符過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • 詳解SpringBoot中時(shí)間類(lèi)型的序列化與反序列化

    詳解SpringBoot中時(shí)間類(lèi)型的序列化與反序列化

    這篇文章主要為大家詳細(xì)介紹了SpringBoot中時(shí)間類(lèi)型的序列化與反序列化的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-02-02
  • java實(shí)現(xiàn)點(diǎn)擊按鈕彈出新窗體功能

    java實(shí)現(xiàn)點(diǎn)擊按鈕彈出新窗體功能

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)點(diǎn)擊按鈕彈出新窗體功能,舊窗體不進(jìn)行操作,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • Java 非靜態(tài)初始化的例子

    Java 非靜態(tài)初始化的例子

    非靜態(tài)初始化和靜態(tài)初始化一模一樣,只不過(guò)少了static關(guān)鍵字。但是如果兩者共存的話(huà),非靜態(tài)初始化是比靜態(tài)初始化慢一拍的。下邊我們舉兩個(gè)例子來(lái)看一下。
    2020-09-09
  • Java編程實(shí)現(xiàn)判斷網(wǎng)上鄰居文件是否存在的方法

    Java編程實(shí)現(xiàn)判斷網(wǎng)上鄰居文件是否存在的方法

    這篇文章主要介紹了Java編程實(shí)現(xiàn)判斷網(wǎng)上鄰居文件是否存在的方法,涉及Java針對(duì)路徑轉(zhuǎn)換及字符串操作的相關(guān)技巧,需要的朋友可以參考下
    2015-10-10

最新評(píng)論

清水河县| 突泉县| 佛学| 蒲江县| 南充市| 抚州市| 库尔勒市| 宁国市| 沙雅县| 宜兴市| 荃湾区| 桂林市| 琼中| 万荣县| 淮安市| 兴安县| 宜良县| 平山县| 北川| 杭锦后旗| 会昌县| 合江县| 宜昌市| 休宁县| 托克托县| 河间市| 华阴市| 大洼县| 吴堡县| 台北市| 津市市| 宝坻区| 灵川县| 哈巴河县| 纳雍县| 东辽县| 丰顺县| 高尔夫| 宁阳县| 甘肃省| 靖宇县|