在以前的面試經歷中,對於String
的考察仍是挺頻繁的,大體考察如下幾個知識點:java
String str3 = "what"; String str4 = str3 + " a nice day"; //運行時, + 至關於 new,因此堆中會有 "what a nice day"對象,常量池中會有"what"," a nice day"兩個對象,而不會有 "what a nice day"對象。 //這句話大佬們看看對不對啊,我怎麼感受不對啊 //常量池不會有"what a nice day" 對象嗎?
看完這個問題,說實話我也是有點懵的,我只是知道 "what a nice day"不會在常量池,可是不知道具體的緣由,後來羣裏的同窗說 + 號是調用了 StringBuffer 的append 方法。我去證明了,發現確實調用了 append 方法,可是當時沒有 調用toString()方法,我很疑惑。(最後通過證明,是StringBuilder的append 方法,不是StringBuffer)。面試
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); }
如今有如下幾個問題,小夥伴們看看是否能答出來,即便答出來了,你知道爲何嗎?微信
#1
str1 存放位置?#2
str2 存放位置?#3
結果是 true 仍是 false?#4
結果是 true 仍是 false?#5
"what a nice day" 存放在哪一個位置呢?下面也不靠猜,咱們直接查看生成的字節碼:app
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
兩個問題。ide
下面咱們看一下 + 操做作了什麼事情,能夠在Code中看到,該操做調用了 StringBuilder.append 方法ui
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;
那麼到這裏一切都答案都出來了this
因此說其實 str1 + " a nice day" 就至關於 new StringBuilder().append(str1).append(" a nice day");code
@Override public String toString() { // 因此說 str2 實際上是一個 new String,是不在常量池裏面的。 return new String(value, 0, count); }
經過類的字節碼能夠查看底層具體用什麼方式實現,因此說雖然看似一個簡單的String問題,其實往深處挖掘仍是考察了對生成的字節碼的理解。還有,遇到一個問題,不能死記答案,有些人告訴你,+ 操做就是 new 對象,可是具體究竟是不是或者爲何是有沒有思考過呢?上文中若有錯誤,歡迎指出。對象