আপনি যখন একটি String
(যা অপরিবর্তনীয় ) পরিবর্তনশীল হিসাবে ঘোষিত করেনfinal
এবং এটি একটি সংকলন-সময় ধ্রুবক অভিব্যক্তি দিয়ে আরম্ভ করেন , এটি একটি সংকলন-সময় ধ্রুবক অভিব্যক্তিও হয়ে যায় এবং এটির মানটি এটি ব্যবহৃত হয় এমন সংকলক দ্বারা অন্তর্ভুক্ত হয়। সুতরাং, আপনার দ্বিতীয় কোড উদাহরণে, মানগুলি অন্তর্ভুক্ত করার পরে, স্ট্রিং কনটেন্টেশনটি অনুবাদক দ্বারা অনুবাদ করেছেন:
String concat = "str" + "ing"; // which then becomes `String concat = "string";`
যা তুলনা করলে "string"
আপনাকে দেবে true
, কারণ স্ট্রিং লিটারেলগুলি ইন্টার্ন করা হয় ।
জেএলএসfinal
থেকে .14.12.4 - পরিবর্তনীয় :
আদিম প্রকার বা প্রকারের একটি পরিবর্তনশীল String
, এটি final
একটি সংকলন-ধ্রুবক অভিব্যক্তি (.215.28) দিয়ে আরম্ভ করা হয়, তাকে ধ্রুবক পরিবর্তনশীল বলা হয় ।
এছাড়াও থেকে JLS §15.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
রানটাইমে কোনও নতুন অবজেক্ট তৈরির সাথে জড়িত নয় । সংকলনের সময়ে স্ট্রিং ইতিমধ্যে পরিচিত এবং সেগুলি ইন্টার্ন করা হয়।