जब आप एक String(जो अपरिवर्तनीय है ) को चर घोषित करते हैं final, और इसे एक संकलन-समय स्थिर अभिव्यक्ति के साथ आरंभ करते हैं, तो यह एक संकलन-समय स्थिर अभिव्यक्ति भी बन जाता है, और इसका मान संकलक द्वारा इनलाइन किया जाता है जहां इसका उपयोग किया जाता है। इसलिए, आपके दूसरे कोड उदाहरण में, मानों को सम्मिलित करने के बाद, संकलक द्वारा स्ट्रिंग संयोजन का अनुवाद किया जाता है:
String concat = "str" + "ing"; // which then becomes `String concat = "string";`
जब आप तुलना "string"करेंगे true, क्योंकि स्ट्रिंग शाब्दिक को नजरबंद कर दिया गया है ।
से JLS §4.12.4 - finalचर :
आदिम प्रकार या प्रकार का एक चर String, जो finalएक संकलन-समय स्थिर अभिव्यक्ति (.215.28) के साथ शुरू होता है, एक स्थिर चर कहलाता है ।
इसके अलावा JLS से .215.28 - लगातार अभिव्यक्ति:
प्रकार का संकलन-समय स्थिर अभिव्यक्ति Stringहमेशा "नजरबंद" होती है, ताकि विधि का उपयोग करके, अद्वितीय उदाहरणों को साझा किया जा सके String#intern()।
यह आपके पहले कोड उदाहरण में नहीं है, जहां Stringचर नहीं हैं final। तो, वे एक संकलन-समय स्थिर अभिव्यक्ति नहीं हैं। इस अवधि के संचालन में विलंब होगा, इस प्रकार एक नई Stringवस्तु के निर्माण की ओर अग्रसर होगा । आप दोनों कोड के बाइट कोड की तुलना करके इसे सत्यापित कर सकते हैं।
पहला कोड उदाहरण (गैर- finalसंस्करण) निम्नलिखित बाइट कोड के लिए संकलित है:
Code:
0: ldc #2; //String str
2: astore_1
3: ldc #3; //String ing
5: astore_2
6: new #4; //class java/lang/StringBuilder
9: dup
10: invokespecial #5; //Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_2
18: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: getstatic #8; //Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_3
29: ldc #9; //String string
31: if_acmpne 38
34: iconst_1
35: goto 39
38: iconst_0
39: invokevirtual #10; //Method java/io/PrintStream.println:(Z)V
42: return
स्पष्ट रूप से यह भंडारण strऔर ingदो अलग-अलग चर में है, और StringBuilderसंघनन ऑपरेशन करने के लिए उपयोग कर रहा है।
जबकि, आपका दूसरा कोड उदाहरण ( finalसंस्करण) इस तरह दिखता है:
Code:
0: ldc #2; //String string
2: astore_3
3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_3
7: ldc #2; //String string
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #4; //Method java/io/PrintStream.println:(Z)V
20: return
तो यह सीधे stringसंकलित करने के लिए अंतिम समय में चर बनाता है , जो ldcचरण में ऑपरेशन द्वारा लोड किया जाता है 0। फिर ldcचरण में ऑपरेशन द्वारा दूसरा स्ट्रिंग शाब्दिक लोड किया जाता है 7। इसमें Stringरनटाइम पर किसी भी नई वस्तु का निर्माण शामिल नहीं है। स्ट्रिंग पहले से ही संकलन समय पर जाना जाता है, और उन्हें नजरबंद कर दिया जाता है।