<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      安卓筆記俠

      專注安卓開發

      導航

      String全面解析

      前言

      public class Test {
          public static void main(String[] args) {
              String a = "abc";
              String b = "abc";
              String c = new String("abc");
              System.out.println(a==b);
              System.out.println(a.equals(b));
              System.out.println(a==c);
              System.out.println(a.equals(c));
          }
      }

      那么上段代碼的結果是什么呢?答案是:true true false true,有初學java的朋友肯定會納悶,a==c為什么會是false呢?equals判斷的為什么都是true呢?

      根據這些問題,我們就通過對String的解讀來一步一步的了解。

      為什么a==c的結果是false

      明白這個問題需要對JVM的內存結構有一定的了解,說是了解也不需要太多,能夠get到下圖的知識點就行了。

      ps:本文中所有的圖示均是為了方便理解,畫出來的大致樣子,如果想要了解的更加清楚,請自行研究虛擬機原理。

       

       

      java語法設計的時候針對String,提供了兩種創建方式和一種特殊的存儲機制(String intern pool )。

      兩種創建字符串對象的方式:

      1. 字面值的方式賦值
      2. new關鍵字新建一個字符串對象

      這兩種方法在性能和內存占用方面存在這差異

      String Pool串池:是在內存堆中專門劃分一塊空間,用來保存所有String對象數據,當構造一個新字符串String對象時(通過字面量賦值的方法),Java編譯機制會優先在這個池子里查找是否已經存在能滿足需要的String對象,如果有的話就直接返回該對象的地址引用(沒有的話就正常的構造一個新對象,丟進去存起來),這樣下次再使用同一個String的時候,就可以直接從串池中取,不需要再次創建對象,也就避免了很多不必要的空間開銷。

      根據以上的概念,我們再來看前言中的代碼,當JVM執行到String a = "abc";的時候,會先看常量池里有沒有字符串剛好是“abc”這個對象,如果沒有,在常量池里創建初始化該對象,并把引用指向它,如下圖。

       

       

      當執行到String b = "abc";時,發現常量池已經有了abc這個值,于是不再在常量池中創建這個對象,而是把引用直接指向了該對象,如下圖:

       

       

      繼續執行到 String c = new String("abc");這時候我們加了一個new關鍵字,這個關鍵字呢就是告訴JVM,你直接在堆內存里給我開辟一塊新的內存,如下圖所示:

       

       

      這時候我們執行四個打印語句,我們需要知道==比較的是地址,equals比較的是內容(String中的重寫過了),abc三個變量的內容完全一樣,因此equals的結果都是true,ab是一個同一個對象,因此地址一樣,a和c很顯然不是同一個對象,那么此時為false也是很好理解的。

      String相關源碼

      在本文中只有String的部分源碼,畢竟String的源碼有3000多行,全部來寫進來不那么現實,我們挑一些比較有意思的代碼來做一定的分析說明。

      屬性

      我們先來看一下String都有哪些成員變量,比較關鍵的屬性有兩個,如下:

      public final class String
          implements java.io.Serializable, Comparable<String>, CharSequence {
          /** The value is used for character storage. */
          char數組
          private final char value[];
          /** Cache the hash code for the string */
          private int hash; // Default to 0
      

      從源碼中我們能夠看到,在String類中聲明了一個char[]數組,變量名value,聲明了一個int類型的變量hash(該String對象的哈希值的緩存)。也就是說java中的String類其實就是對char數組的封裝。

      構造方法

      接下來我們通過一句代碼來了解一下字符串創建的過程,String c = new String("abc");我們知道使用new關鍵字就會使用到構造方法,所以如下。

      public String(String original) {
              this.value = original.value;
              this.hash = original.hash;
          }
      

      構造方法中的代碼非常簡單,把傳進來的字符串的value值,也就是char數組賦值給當前對象,hash同樣處理,那么問題來了WTF original?

      在這里需要注意的是java中的一個機制,在Java中,當值被雙引號引起來(如本示例中的"abc"),JVM會去先檢查看一看常量池里有沒有abc這個對象,如果沒有,把abc初始化為對象放入常量池,如果有,直接返回常量池內容。所以也就是說在沒有“abc”的基礎上,執行代碼會在串池中創建一個abc,也會在堆內存中再new出來一個。最終的結果如下圖:

       

      String4

       

      那么這時候如果再有一個String c2 = new String("abc");呢?如圖

       

      String5

       

      關于這一點我們通過IDEA的debug功能也能夠看到,你會發現,c和c2其中的char數組的地址是相同的。足以說明在創建c和c2的時候使用的是同一個數組。

       

       

      equals方法

      public boolean equals(Object anObject) {
           //如果兩個對象是同一個引用,那么直接返回true
              if (this == anObject) {
                  return true;
              }
           /*
           1.判斷傳入的對象是不是String類型
           2.判斷兩個對象的char數組長度是否一致
           3.循環判斷char數組中的每一個值是否相等
           以上條件均滿足才會返回true
           */
              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;
          }
      

      為什么String不可變?

      串池需要

      為什么說是串池需要呢?在開篇的時候我們提到過,串池中的字符串會被多個變量引用,這樣的機制讓字符串對象得到了復用,避免了很多不必要的內存消耗。

      那么大家試想一下,如果String對象本身允許二次修改的話,我有一個字符串“abc”同時被100個變量引用,其中一個引用修改了String對象,那么將會影響到其他99個引用該對象的變量,這樣會對其他變量造成不可控的影響。

      不可變性的優點

      安全性

      字符串不可變安全性的考慮處于兩個方面,數據安全和線程安全。

      數據安全,大家可以回憶一下,我們都在哪些地方大量的使用了字符串?網絡數據傳輸,文件IO等,也就是說當我們在傳參的時候,使用不可變類不需要去考慮誰可能會修改其內部的值,如果使用可變類的話,可能需要每次記得重新拷貝出里面的值,性能會有一定的損失。

      線程安全,因為字符串是不可變的,所以是多線程安全的,同一個字符串實例可以被多個線程共享,這樣便不用因為線程安全問題而使用同步。

      性能效率

      關于性能效率一方面是復用,另一方面呢需要從hash值的緩存方向來說起了。

      String的Hash值在很多的地方都會被使用到,如果保證了String的不可變性,也就能夠保證Hash值始終也是不可變的,這樣就不需要在每次使用的時候重新計算hash值了。

      String不可變性是如何實現的?

      通過對屬性私有化,final修飾,同時沒有提供公開的get set方法以及其他的能夠修改屬性的方法,保證了在創建之后不會被從外部修改。

      同時不能忘了,String也是被final修飾的,在之前的文章中我們提到過,final修飾類的結果是String類沒有子類。

      那么String真的不能改變嗎?不是,通過反射我們可以,代碼如下:

      String c = new String("abc");
      System.out.println(c);
      //獲取String類中的value字段
      Field valueFieldOfString = String.class.getDeclaredField("value");
      
      //改變value屬性的訪問權限
      valueFieldOfString.setAccessible(true);
      
      //獲取s對象上的value屬性的值
      char[] value = (char[]) valueFieldOfString.get(c);
      
      //改變value所引用的數組中的第5個字符
      value[1] = '_';
      System.out.println(c);
      執行的結果是
      
      abc
      a_c
      

      也就是說我們改變了字符串對象的值,有什么意義呢?沒什么意義,我們從來不會這么做。

      其他問題

      不是特別需要請不要使用new關鍵字創建字符串

      從前文我們知道使用new關鍵字創建String的時候,即便串池中存在相同String,仍然會再次在堆內存中創建對象,會浪費內存,另一方面對象的創建相較于從串池中取效率也更低下。

      String StringBuffer StringBuilder的區別

      關于三者的區別,在面試題中經常的出現,String對象不可變,因此在進行任何內容上的修改時都會創建新的字符串對象,一旦修改操作太多就會造成大量的資源浪費。

      StringBuffer和StringBuilder在進行字符串拼接的時候不會創建新的對象,而是在原對象上修改,不同之處在于StringBuffer線程安全,StringBuilder線程不安全。所以在進行字符串拼接的時候推薦使用StringBuffer或者StringBuilder。

        

        

        

        

       

      posted on 2016-11-15 23:30  安卓筆記俠  閱讀(994)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 格尔木市| 亚洲欧美在线观看品| 亚洲深夜精品在线观看| 全国最大成人网| 2019香蕉在线观看直播视频| 韩国无码AV片在线观看网站| 国产乱子伦视频在线播放| 国产无遮挡真人免费视频| 在线中文字幕国产精品| a∨变态另类天堂无码专区| 老色99久久九九爱精品| 国产成人8X人网站视频| 日韩在线观看精品亚洲| 久久久久无码中| 亚洲AV无码成人网站久久精品| 久久91精品牛牛| 亚洲少妇一区二区三区老| 国产午夜福利精品久久不卡| 亚洲人妻一区二区精品| 黄色国产精品一区二区三区| 天天躁日日躁狠狠躁中文字幕| 丁香婷婷综合激情五月色| 国产亚洲精品VA片在线播放| 色综合色综合久久综合频道88| 久久亚洲精品11p| 一级女性全黄久久生活片| 久久亚洲精品中文字幕馆| 成人乱人伦精品小说| 国产亚洲精品第一综合另类无码无遮挡又大又爽又黄的视频 | 男人的天堂va在线无码| 国产黄色三级三级看三级| 欧美牲交a欧美牲交aⅴ图片| 久久国产成人高清精品亚洲| 日韩美女亚洲性一区二区| 亚洲日本精品一区二区| 欧洲精品色在线观看| 国产精品国产三级国av| 欧美国产精品不卡在线观看| 武装少女在线观看高清完整版免费 | 亚洲av成人一区二区三区| 4hu亚洲人成人无码网www电影首页|