এর সাথে স্ট্রিংগুলির তুলনা == যা জাভাতে চূড়ান্ত ঘোষণা করা হয়েছে


220

জাভাতে স্ট্রিং সম্পর্কে আমার একটি সাধারণ প্রশ্ন আছে। সাধারণ কোডের নিম্নলিখিত বিভাগটি কেবল দুটি স্ট্রিংকে যুক্ত করে এবং তার সাথে তাদের তুলনা করে ==

String str1="str";
String str2="ing";
String concat=str1+str2;

System.out.println(concat=="string");

তুলনা অভিব্যক্তি concat=="string"আয় falseসুস্পষ্ট যেমন (আমি মধ্যে পার্থক্য বুঝতে equals()এবং ==)।


এই দুটি স্ট্রিং যখন এর finalমতো ঘোষিত হয় ,

final String str1="str";
final String str2="ing";
String concat=str1+str2;

System.out.println(concat=="string");

concat=="string"এই ক্ষেত্রে তুলনা প্রকাশ true। কেন finalএকটি পার্থক্য আছে? এটি কি ইন্টার্ন পুল দিয়ে কিছু করতে পারে বা আমি কেবল বিভ্রান্ত হচ্ছি?


22
আমি সর্বদা এটি নির্বাক দেখতে পেলাম যে সমান বিষয়বস্তুগুলির জন্য == থাকার পরিবর্তে সমান বিষয়গুলি পরীক্ষা করার ডিফল্ট উপায় ছিল এবং কেবলমাত্র রেফারেন্সএকুয়ালস বা পয়েন্টারগুলি একই কিনা তা যাচাই করার জন্য অনুরূপ কিছু ব্যবহার করুন।
ডেভিও

25
এটি "জাভাতে স্ট্রিংগুলি কীভাবে তুলনা করব?" এর সদৃশ নয় ? যেকোন ভাবে. ওপি স্ট্রিংগুলির প্রসঙ্গে equals()এবং এর ==মধ্যে পার্থক্যটি বোঝে এবং আরও অর্থবহ প্রশ্ন জিজ্ঞাসা করছে।
আরশাজী

@ ডেভিও কিন্তু ক্লাস না থাকলে Stringকীভাবে কাজ করবে ? আমি মনে করি এটি অত্যন্ত যুক্তিসঙ্গত, মূর্খ নয়, এর সাথে সামগ্রীগুলির তুলনা করা equals, এমন একটি পদ্ধতি যা আমরা দুটি বিষয়কে সমান বিবেচনা করি এবং তা দিয়ে পরিচয়ের তুলনাটি সম্পন্ন করার জন্য আমরা ওভাররাইড করতে পারি ==। যদি বিষয়গুলির তুলনা করা হয় তবে ==আমরা "সমান বিষয়বস্তু" বলতে যা বোঝায় তা সংজ্ঞায়িত করতে আমরা ওভাররাইড করতে পারি না, এবং এর অর্থ equalsএবং ==কেবল এর জন্য বিপরীত Stringহওয়া নির্বিকার। এছাড়াও, এটিকে নির্বিশেষে, আমি ==সামগ্রীর তুলনায় এর তুলনায় আর কোনও লাভ দেখছি না equals
সান্টিবাইলার্স

@ সাঁতিবিলোররা আপনারা ঠিক বলেছেন যে এটি জাভাতে ঠিক কীভাবে কাজ করে, আমি সি # ব্যবহার করেছি যেখানে == সামগ্রী সমতার জন্য অতিরিক্ত লোড করা হয়েছে। == ব্যবহারের একটি যুক্ত বোনাস হ'ল এটি নাল-নিরাপদ: (নাল == "কিছু") মিথ্যা ফেরত দেয়। আপনি যদি 2 টি সামগ্রীর জন্য সমান ব্যবহার করেন, তবে আপনাকে সচেতন হতে হবে যদি হয় নাল হতে পারে বা আপনি নালপয়েন্টার এক্সসেপশন নিক্ষেপ করার ঝুঁকি নিয়ে থাকেন।
ডেভিও

উত্তর:


232

আপনি যখন একটি 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রানটাইমে কোনও নতুন অবজেক্ট তৈরির সাথে জড়িত নয় । সংকলনের সময়ে স্ট্রিং ইতিমধ্যে পরিচিত এবং সেগুলি ইন্টার্ন করা হয়।


2
চূড়ান্ত স্ট্রিং ডানদিকে ইন্টার্ন না করে অন্যান্য জাভা সংকলক প্রয়োগকে বাধা দেওয়ার কিছুই নেই?
অ্যালভিন

13
অ্যালভিন জেএলএসের প্রয়োজন যে সংকলন-সময় ধ্রুব স্ট্রিং এক্সপ্রেশনগুলি ইন্টার্ন করা উচিত। যে কোনও মেনে চলার বাস্তবায়ন অবশ্যই এখানে একই কাজ করতে হবে।
তাভিয়ান বার্নস

বিপরীতভাবে, জেএলএস আদেশ দেয় যে কোনও সংকলক অবশ্যই প্রথম, চূড়ান্ত সংস্করণে উপসংহারটি অনুকূল করতে পারে না ? সংকলক কোড উত্পাদন করা থেকে নিষিদ্ধ, যে তুলনা মূল্যায়ন করতে হবে true?
ফ্যান্ট0 মি

1
@ বর্তমান বাক্যে কথন গ্রহণ phant0m স্পেসিফিকেশন , " বস্তুর নব নির্মিত হয় (§12.5) যদি না অভিব্যক্তি একটি ধ্রুবক অভিব্যক্তি (§15.28) হয়। "আক্ষরিক অর্থে, চূড়ান্ত-অ-সংস্করণে একটি অপ্টিমাইজেশান প্রয়োগ করার অনুমতি নেই, কারণ" নতুন তৈরি "স্ট্রিংয়ের অবশ্যই পৃথক বস্তুর পরিচয় থাকতে হবে। আমি জানি না এটি ইচ্ছাকৃত কিনা। সর্বোপরি, বর্তমান সংকলন কৌশলটি একটি রানটাইম সুবিধার জন্য প্রেরণ করা যা এই জাতীয় বিধিনিষেধগুলিকে দলিল করে না। String
হলগার

31

আমার গবেষণা অনুসারে, final Stringসমস্তগুলি জাভাতে অন্তর্ভুক্ত। ব্লগ পোস্টের একটি থেকে:

সুতরাং, আপনার যদি সত্যিই == বা! = ব্যবহার করে দুটি স্ট্রিংয়ের তুলনা করতে চান তবে তুলনা করার আগে আপনি স্ট্রিং.ইনটার্ন () পদ্ধতিটি কল করেছেন তা নিশ্চিত করুন। অন্যথায়, স্ট্রিং তুলনার জন্য সর্বদা String.equals (স্ট্রিং) পছন্দ করুন।

সুতরাং এর অর্থ যদি আপনি কল করেন তবে অপারেটর String.intern()ব্যবহার করে দুটি স্ট্রিং তুলনা করতে পারবেন ==। তবে এখানে String.intern()প্রয়োজনীয় নয় কারণ জাভা final Stringঅভ্যন্তরীণভাবে অভ্যন্তরীণ।

স্ট্রিং.ইনটার্ন () পদ্ধতির জন্য অপারেটর এবং জাভাদোক ব্যবহার করে স্ট্রিংয়ের তুলনা আরও পেতে পারেন ।

আরও তথ্যের জন্য এই স্ট্যাকওভারফ্লো পোস্টটি দেখুন।


3
ইন্টার্ন () স্ট্রিংগুলি আবর্জনা সংগ্রহ করা হয় না এবং এটি পার্জেন স্পেসে সঞ্চিত থাকে যা কম থাকে তাই সঠিকভাবে ব্যবহার না করা হলে আপনি স্মৃতি ত্রুটির বাইরে যাওয়ার মতো সমস্যায় পড়বেন ।
আজীশ

@ আজিশ - অভ্যন্তরীণ স্ট্রিংগুলি আবর্জনা সংগ্রহ করা যেতে পারে। এমনকি ধ্রুবক প্রকাশের ফলে অভ্যন্তরীণ স্ট্রিংগুলি কিছু পরিস্থিতিতে আবর্জনা সংগ্রহ করা যেতে পারে।
স্টিফেন সি

21

আপনি যদি এই পদ্ধতিগুলি একবার দেখুন

public void noFinal() {
    String str1 = "str";
    String str2 = "ing";
    String concat = str1 + str2;

    System.out.println(concat == "string");
}

public void withFinal() {
    final String str1 = "str";
    final String str2 = "ing";
    String concat = str1 + str2;

    System.out.println(concat == "string");
}

এবং এটি javap -c ClassWithTheseMethods দেখতে পাবেন সংস্করণগুলির সাথে এর পচন

  public void noFinal();
    Code:
       0: ldc           #15                 // String str
       2: astore_1      
       3: ldc           #17                 // String ing
       5: astore_2      
       6: new           #19                 // class java/lang/StringBuilder
       9: dup           
      10: aload_1       
      11: invokestatic  #21                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
      14: invokespecial #27                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      17: aload_2       
      18: invokevirtual #30                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: invokevirtual #34                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      ...

এবং

  public void withFinal();
    Code:
       0: ldc           #15                 // String str
       2: astore_1      
       3: ldc           #17                 // String ing
       5: astore_2      
       6: ldc           #44                 // String string
       8: astore_3      
       ...

সুতরাং স্ট্রিংগুলি যদি চূড়ান্ত না হয় তবে সংমিশ্রনের জন্য ব্যবহার StringBuilderকরতে হবে str1এবং str2তাই

String concat=str1+str2;

সংকলিত হবে

String concat = new StringBuilder(str1).append(str2).toString();

যার অর্থ concatরানটাইম তৈরি করা হবে তাই স্ট্রিং পুল থেকে আসবে না।


স্ট্রিংস যদি চূড়ান্ত হয় তবে সংকলক ধরে নিতে পারে যে তারা কখনই পরিবর্তিত হবে না StringBuilderএটি ব্যবহার করার পরিবর্তে এটির মানগুলি নিরাপদে প্রকাশ করতে পারে

String concat = str1 + str2;

থেকে পরিবর্তন করা যেতে পারে

String concat = "str" + "ing";

এবং সংক্ষিপ্ত

String concat = "string";

যার অর্থ concateস্টিং আক্ষরিক হয়ে উঠবে যা স্ট্রিং পুলে অন্তর্ভুক্ত হবে এবং তারপরে ifবিবৃতিতে সেই পুল থেকে একই স্ট্রিং আক্ষরিকের সাথে তুলনা করা হবে ।


15

স্ট্যাক এবং স্ট্রিং কনট পুল ধারণা এখানে চিত্র বর্ণনা লিখুন


6
কি? আমি বুঝতে পারি না এর কীভাবে উপকার হয়েছে। আপনি কি আপনার উত্তর পরিষ্কার করতে পারেন?
সি

আমার মনে হয় উদ্দেশ্যযুক্ত উত্তরটি হ'ল যেহেতু str1 + str2 কোনও অভ্যন্তরীণ স্ট্রিংকে অনুকূলিত করা হয়নি, স্ট্রিং পুলের সাথে একটি স্ট্রিংয়ের সাথে তুলনা করা একটি মিথ্যা শর্তের দিকে নিয়ে যাবে।
viki.omega9

3

finalউদাহরণস্বরূপ কিছু বাইট কোড দেখুন

Compiled from "Main.java"
public class Main {
  public Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.Exception;
    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
}

0:এবং 2:, String "string"(ধ্রুব পুকুর থেকে) স্ট্যাক সম্মুখের ধাক্কা এবং স্থানীয় পরিবর্তনশীল মধ্যে সংরক্ষিত হয় concatসরাসরি। String "string"সংকলনের সময় সংকলক নিজেই তৈরি করছে (বোঝাচ্ছে) ded

নন finalবাইট কোড

Compiled from "Main2.java"
public class Main2 {
  public Main2();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]) throws java.lang.Exception;
    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/Stri
ngBuilder;
      17: aload_2
      18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
      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
}

এখানে আপনার কাছে দুটি Stringধ্রুবক রয়েছে "str"এবং "ing"যা রানটাইম এ ক এর সাথে সংঘবদ্ধ হওয়া দরকার StringBuilder


0

যদিও আপনি যখন জাভার স্ট্রিং আক্ষরিক স্বরলিপি ব্যবহার করে তৈরি করেন, এটি স্বয়ংক্রিয়ভাবে ইন্টার্ন () পদ্ধতিতে স্ট্রিং পুলে intoোকানোর জন্য কল করে, তবে শর্ত থাকে যে এটি ইতিমধ্যে পুলটিতে উপস্থিত না থাকলে।

চূড়ান্ত কেন একটি পার্থক্য করে?

সংকলক চূড়ান্ত ভেরিয়েবলটি কখনই পরিবর্তন করতে পারবে না জানে, যখন আমরা এই চূড়ান্ত ভেরিয়েবলগুলি যুক্ত করি তখন আউটপুট স্ট্রিং পুলে যায় কারণ str1 + str2এক্সপ্রেশন আউটপুটটিও কখনই পরিবর্তন করতে পারে না, সুতরাং শেষ পর্যন্ত সংকলক উপরের দুটি চূড়ান্ত ভেরিয়েবলের আউটপুট পরে ইন্টার পদ্ধতিতে কল করে। চূড়ান্ত নয় এমন ক্ষেত্রে চলক সংকলক ইন্টার্ন পদ্ধতিতে কল করবেন না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.