前言

          ?在之前的面試經(jīng)歷中,對于String的考察還是挺頻繁的,大致考察以下幾個(gè)知識(shí)點(diǎn):

          * String 常量池
          * new String()
          * == 和 equals 的區(qū)別
          * native 方法 String.intern()
          雖然面試中大體答對了,但是今天早上微信群里的一個(gè)問題我卻答不上來,這個(gè)問題是這樣的: String str3 = "what"; String str4
          = str3 + " a nice day"; //運(yùn)行時(shí), + 相當(dāng)于 new,所以堆中會(huì)有 "what a nice
          day"對象,常量池中會(huì)有"what"," a nice day"兩個(gè)對象,而不會(huì)有 "what a nice day"對象。
          //這句話大佬們看看對不對啊,我怎么感覺不對啊 //常量池不會(huì)有"what a nice day" 對象嗎?
          看完這個(gè)問題,說實(shí)話我也是有點(diǎn)懵的,我只是知道 "what a nice day"不會(huì)在常量池,但是不知道具體的原因,后來群里的同學(xué)說 + 號(hào)是調(diào)用了
          StringBuffer 的append 方法。我去證實(shí)了,發(fā)現(xiàn)確實(shí)調(diào)用了 append 方法,但是當(dāng)時(shí)沒有
          調(diào)用toString()方法,我很疑惑。(最后經(jīng)過證實(shí),是StringBuilder的append 方法,不是StringBuffer)。

          代碼驗(yàn)證
          public static void main(String[] args) { //#1 String str1 = "what"; //#2
          String str2 = str1 + " a nice day"; //#3 System.out.println("what a nice
          day".equals(str2)); //#4 System.out.println("what a nice day" == str2); }
          現(xiàn)在有以下幾個(gè)問題,小伙伴們看看是否能答出來,即使答出來了,你知道為什么嗎?

          * #1 str1 存放位置?
          * #2 str2 存放位置?
          * #3 結(jié)果是 true 還是 false?
          * #4 結(jié)果是 true 還是 false?
          * #5 "what a nice day" 存放在哪個(gè)位置呢?
          解答分析(基于JDK1.8)

          下面也不靠猜,我們直接查看生成的字節(jié)碼:
          localhost:test didi$ javap -verbose -p Main.class Classfile
          /develop/project/string-test/out/production/classes/com/fanpan26/string/test/Main.class
          Last modified 2019-11-29; size 972 bytes MD5 checksum
          1d1f1a23bfe85c2f88d2f767e8aac314 Compiled from "Main.java" public class
          com.fanpan26.string.test.Main minor version: 0 major version: 52 flags:
          ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #13.#34 //
          java/lang/Object."<init>":()V #2 = String #35 // what #3 = Class #36 //
          java/lang/StringBuilder #4 = Methodref #3.#34 //
          java/lang/StringBuilder."<init>":()V #5 = Methodref #3.#37 //
          java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #6
          = String #38 // a nice day #7 = Methodref #3.#39 //
          java/lang/StringBuilder.toString:()Ljava/lang/String; #8 = Fieldref #40.#41 //
          java/lang/System.out:Ljava/io/PrintStream; #9 = String #42 // what a nice day
          #10 = Methodref #43.#44 // java/lang/String.equals:(Ljava/lang/Object;)Z #11 =
          Methodref #45.#46 // java/io/PrintStream.println:(Z)V #12 = Class #47 //
          com/fanpan26/string/test/Main #13 = Class #48 // java/lang/Object #14 = Utf8
          <init> #15 = Utf8 ()V #16 = Utf8 Code #17 = Utf8 LineNumberTable #18 = Utf8
          LocalVariableTable #19 = Utf8 this #20 = Utf8 Lcom/fanpan26/string/test/Main;
          #21 = Utf8 main #22 = Utf8 ([Ljava/lang/String;)V #23 = Utf8 args #24 = Utf8
          [Ljava/lang/String; #25 = Utf8 str1 #26 = Utf8 Ljava/lang/String; #27 = Utf8
          str2 #28 = Utf8 StackMapTable #29 = Class #24 // "[Ljava/lang/String;" #30 =
          Class #49 // java/lang/String #31 = Class #50 // java/io/PrintStream #32 = Utf8
          SourceFile #33 = Utf8 Main.java #34 = NameAndType #14:#15 // "<init>":()V #35 =
          Utf8 what #36 = Utf8 java/lang/StringBuilder #37 = NameAndType #51:#52 //
          append:(Ljava/lang/String;)Ljava/lang/StringBuilder; #38 = Utf8 a nice day #39
          = NameAndType #53:#54 // toString:()Ljava/lang/String; #40 = Class #55 //
          java/lang/System #41 = NameAndType #56:#57 // out:Ljava/io/PrintStream; #42 =
          Utf8 what a nice day #43 = Class #49 // java/lang/String #44 = NameAndType
          #58:#59 // equals:(Ljava/lang/Object;)Z #45 = Class #50 // java/io/PrintStream
          #46 = NameAndType #60:#61 // println:(Z)V #47 = Utf8
          com/fanpan26/string/test/Main #48 = Utf8 java/lang/Object #49 = Utf8
          java/lang/String #50 = Utf8 java/io/PrintStream #51 = Utf8 append #52 = Utf8
          (Ljava/lang/String;)Ljava/lang/StringBuilder; #53 = Utf8 toString #54 = Utf8
          ()Ljava/lang/String; #55 = Utf8 java/lang/System #56 = Utf8 out #57 = Utf8
          Ljava/io/PrintStream; #58 = Utf8 equals #59 = Utf8 (Ljava/lang/Object;)Z #60 =
          Utf8 println #61 = Utf8 (Z)V { public com.fanpan26.string.test.Main();
          descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0:
          aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return
          LineNumberTable: line 6: 0 LocalVariableTable: Start Length Slot Name Signature
          0 5 0 this Lcom/fanpan26/string/test/Main; public static void
          main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC,
          ACC_STATIC Code: stack=3, locals=3, args_size=1 0: ldc #2 // String what 2:
          astore_1 3: new #3 // class java/lang/StringBuilder 6: dup 7: invokespecial #4
          // Method java/lang/StringBuilder."<init>":()V 10: aload_1 11: invokevirtual #5
          // Method
          java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          14: ldc #6 // String a nice day 16: invokevirtual #5 // Method
          java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          19: invokevirtual #7 // Method
          java/lang/StringBuilder.toString:()Ljava/lang/String; 22: astore_2 23:
          getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream; 26: ldc #9 //
          String what a nice day 28: aload_2 29: invokevirtual #10 // Method
          java/lang/String.equals:(Ljava/lang/Object;)Z 32: invokevirtual #11 // Method
          java/io/PrintStream.println:(Z)V 35: getstatic #8 // Field
          java/lang/System.out:Ljava/io/PrintStream; 38: ldc #9 // String what a nice day
          40: aload_2 41: if_acmpne 48 44: iconst_1 45: goto 49 48: iconst_0 49:
          invokevirtual #11 // Method java/io/PrintStream.println:(Z)V 52: return
          LineNumberTable: line 9: 0 line 11: 3 line 13: 23 line 15: 35 line 16: 52
          LocalVariableTable: Start Length Slot Name Signature 0 53 0 args
          [Ljava/lang/String; 3 50 1 str1 Ljava/lang/String; 23 30 2 str2
          Ljava/lang/String; StackMapTable: number_of_entries = 2 frame_type = 255 /*
          full_frame */ offset_delta = 48 locals = [ class "[Ljava/lang/String;", class
          java/lang/String, class java/lang/String ] stack = [ class java/io/PrintStream
          ] frame_type = 255 /* full_frame */ offset_delta = 0 locals = [ class
          "[Ljava/lang/String;", class java/lang/String, class java/lang/String ] stack =
          [ class java/io/PrintStream, int ] } SourceFile: "Main.java"
          從 Constant pool: 中的信息可以看到,#2 #6 #9 可以解答上文中的#1,#5兩個(gè)問題。

          * str1 是存放在常量池的
          * "what a nice day" (非str2)也是存放在常量池的.
          下面我們看一下 + 操作做了什么事情,可以在Code中看到,該操作調(diào)用了 StringBuilder.append 方法
          11: invokevirtual #5 // Method
          java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          14: ldc #6 // String a nice day 16: invokevirtual #5 // Method
          java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          19: invokevirtual #7 // Method
          java/lang/StringBuilder.toString:()Ljava/lang/String;
          那么到這里一切都答案都出來了

          * str2 是存放在堆中。
          * equals 為 true
          * == 為 false
          所以說其實(shí) str1 + " a nice day" 就相當(dāng)于 new StringBuilder().append(str1).append(" a
          nice day");
          //這兩種寫法生成的字節(jié)碼是一樣的。 //String str2 = str1 + " a nice day"; String str2 = new
          StringBuilder().append(str1).append(" a nice day").toString();
          而StringBuilder 的toString 方法如下:
          @Override public String toString() { // 所以說 str2 其實(shí)是一個(gè) new String,是不在常量池里面的。
          return new String(value, 0, count); }
          總結(jié)


          通過類的字節(jié)碼可以查看底層具體用什么方式實(shí)現(xiàn),所以說雖然看似一個(gè)簡單的String問題,其實(shí)往深處挖掘還是考察了對生成的字節(jié)碼的理解。還有,遇到一個(gè)問題,不能死記答案,有些人告訴你,+
          操作就是 new 對象,但是具體到底是不是或者為什么是有沒有思考過呢?上文中如有錯(cuò)誤,歡迎指出。

          試一試
          /** * 以下程序輸出的結(jié)果是什么? * */ public static void main(String[] args) { String str1
          = "what"; String str2 = str1 + " a nice day"; System.out.println("what a nice
          day".equals(str2)); System.out.println("what a nice day" == str2); } /** *
          以下程序輸出的結(jié)果是什么? * */ public static void main(String[] args) { String str1 = "what
          a nice day"; String str2 = new String("what a nice day");
          System.out.println(str1.equals(str2)); System.out.println(str1 == str2); } /**
          * 以下程序輸出的結(jié)果是什么? * */ public static void main(String[] args) { String str1 =
          "what"; String str2 = str1.concat(" a nice day"); System.out.println("what a
          nice day".equals(str2)); System.out.println("what a nice day" == str2);
          System.out.println("what a nice day"==str2.intern()); }

          友情鏈接
          ioDraw流程圖
          API參考文檔
          OK工具箱
          云服務(wù)器優(yōu)惠
          阿里云優(yōu)惠券
          騰訊云優(yōu)惠券
          京東云優(yōu)惠券
          站點(diǎn)信息
          問題反饋
          郵箱:[email protected]
          QQ群:637538335
          關(guān)注微信

                天天干天天操综合网 | 狼人伊人在线 | 亚洲无码专区在线观看 | 68精品国产免费久久久久久婷婷 | 香港三日三级少妇三级66 |