یک نکتهء مهم در برنامه نویسی جاوا/اندروید

اخیرا شروع به نوشتن یه برنامه اندروید کردم که در این جریان به باگ عجیبی برخورد کردم که چند ساعتی باهاش سر و کله زدم تا آخر فهمیدم علتش چیه.

جالب اینکه مدت خیلی کوتاهی قبلش، یک نفر دیگر هم ظاهرا به مشکلی در کدش برخورد کرده بود که احتمال زیاد به همین قضیه مربوط میشد، و در یک فروم در این مورد سوال کرده بود که حتی منم جوابش رو دادم و گزینه هایی که بنظرم محتمل بود بهش گفتم.

چون خیلی از برنامه نویسان اندروید ممکنه قبلا برنامه نویسی به زبان جاوا نکرده باشن و این زبان رو بصورت جدی و کامل یاد نگرفته باشن، مثل خودم، پس زیاد ممکنه با چنین مشکلی روبرو بشن و بنابراین فکر میکنم ذکر این مورد بتونه برای خیلی ها مفید باشه و از اتلاف وقت و انرژی و ایجاد باگ در برنامه ها جلوگیری کنه.

خب دیگه بیشتر حاشیه نمیرم و یک راست با کد و مثال، مورد مذکور رو شرح میدم:

حاصل اجرای این کد:
String s1="abc";
String s2="abc";
System.out.println(s1==s2);

طبق انتظار، true خواهد بود. یعنی حاصل مقایسهء دو رشتهء s1 و s2 بر اساس مقدارشون که یکسان است، true است. البته توجه دارید که من بجای اینکه s1==s2 رو توی دستور if بذارم، مستقیما در دستور println گذاشتم که کد مثال کوتاهتر و خواناتر باشه.
خب تا اینجا مشکلی نیست و همه چیز طبق انتظار و بنظرم مشابه تقریبا تمام زبانهای برنامه نویسی دیگر کار میکنه.

اما خروجی این کد:
String s1=new String("abc");
String s2=new String("abc");
System.out.println(s1==s2);

کاسه کوزهء ما رو بهم میریزه، چون false چاپ میشه!!

و همچنین این کد:
String s1="abc";
String s2=new String("abc");
System.out.println(s1==s2);

نتیجهء مشابهی داره.

خب چرا اینطوریه؟
جوابش اینه که در جاوا Object ها، حتی از نوع String، بر اساس رفرنسشون مقایسه میشن. یعنی در حالتی که ما از new برای ایجاد رشته استفاده کردیم (که در این حالت متغییر ما در حافظهء Heap ایجاد میشه)، مقایسه بر اساس آدرس خود شیء صورت میگیره و نه بر اساس محتویاتش. یعنی شرط s1==s2 در این حالت بررسی میکنه که آیا s1 و s2 درواقع هردو به یک شیء یکسان در حافظه اشاره میکنن یا نه.

البته این رفتار جاوا درمورد رشته ها واقعا غیرمنتظره هست و من یاد ندارم در زبان دیگری چنین چیزی دیده باشم.

من شخصا خیلی سردرگم شده بودم چون کد من به این سادگی نبود که دوتا متغییر مورد مقایسه رو خودم ایجاد کرده باشم و از روش ایجاد اونا خبر داشته باشم و جلوی چشمم باشه. من داشتم یک رشتهء ثابت (Literal) رو با رشته ای که یک متدی از یک شیء از یک کتابخانه ای برمیگردوند مقایسه میکردم، و نمیدونستم توی اون کتابخانه داره چی رخ میده و رشتهء مورد نظر با عملگر new ایجاد شده.

خیله خب، با اینکه عجیبه ولی مشکلی نیست، ولی پس راه حلش چیه؟ چطوری میتونیم دوتا رشته رو مقایسه کنیم بدون اینکه احتمال داشته باشه دچار این مسئله بشیم؟

پاسخ اینه:
String s1="abc";
String s2="abc";
System.out.println(s1.equals(s2));

متغییرهای/اشیاء رشته ای یک متد دارن بنام equals که برای همین کاره؛ یعنی مقایسهء برابری مقدار محتوی رشته.

حالا کد و مشکل من حتی از این هم پیچیده تر بود، چون متدی که گفتم یک رشته برمیگردوند میتونست در شرایط خاصی null هم برگردونه، که در این حالت null دیگه چنان شیء ای نیست که متد equals داشته باشه، و بنابراین کد در این حالت با خطای زمان اجرا مواجه میشد. ولی خوشبختانه متد equals حتی با رشته هایی که بصورت مستقیم در کد درج شدن هم وجود داره و کار میکنه، و من توی شرطم چنین کدی نوشتم:
"some string".equals(someObj.someMethod())

1 دیدگاه در “یک نکتهء مهم در برنامه نویسی جاوا/اندروید

  1. سلام
    باز حقیر مزاحم شما شدم.
    به روند شما یعنی خواندن رفرنس ها یادگیری جاوا را شروع کردم.
    نکته ای که فهمیدم این بود، بهتر است از همین رفرنس خواندن به یادگیری زبان بپردازم. زیرا دانستم که اگر هوش و تواناییی هایی به اندازه شما هم داشته باشم اگر به مسئله “اساسی” برسم که نخوانده ام عقلم به جایی قد نخواهد داد. البته این را از روی بخش زیر در رفرنس جاوا پیدا کردم چرا که اگر شما آن را میخواندید به هیچ وجه دچار این مشکل نمیشدید :

    The equals() Method

    The equals() method compares two objects for equality and returns true if they are equal. The equals() method provided in the Object class uses the identity operator (==) to determine whether two objects are equal. For primitive data types, this gives the correct result. For objects, however, it does not. The equals() method provided by Object tests whether the object references are equal—that is, if the objects compared are the exact same object.

    To test whether two objects are equal in the sense of equivalency (containing the same information), you must override the equals() method.

    اما به قطع و به یقین میدانم اگر به زبان تسلط پیدا نکنم به مشکلاتی برخورد خواهم کرد که حلش بیشتر از رفرنس خوانی طول خواهد کشید.

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

*

شما می‌توانید از این دستورات HTML استفاده کنید: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>