जब आप एक 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
रनटाइम पर किसी भी नई वस्तु का निर्माण शामिल नहीं है। स्ट्रिंग पहले से ही संकलन समय पर जाना जाता है, और उन्हें नजरबंद कर दिया जाता है।