<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های هادی درتاج</title>
        <link>https://virgool.io/feed/@hadidortaj</link>
        <description>برنامه نویس اندروید</description>
        <language>fa</language>
        <pubDate>2026-04-15 03:47:52</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/122421/avatar/L9FXbE.jpg?height=120&amp;width=120</url>
            <title>هادی درتاج</title>
            <link>https://virgool.io/@hadidortaj</link>
        </image>

                    <item>
                <title>آشنایی با قوانین SOLID - به همراه مثال</title>
                <link>https://virgool.io/@hadidortaj/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-%D9%82%D9%88%D8%A7%D9%86%DB%8C%D9%86-solid-%D8%A8%D9%87-%D9%87%D9%85%D8%B1%D8%A7%D9%87-%D9%85%D8%AB%D8%A7%D9%84-el936lfq4tid</link>
                <description>شاید کم تر برنامه نویسی باشه که تو آگهی های استخدام عبارت &quot;آشنایی با قوانین SOLID&quot; رو ندیده باشه. یادگیری این قوانین کد نویسی تبدیل به جزء جداناپذیر برنامه نویسی شده و توصیه میشه تا حد امکان هنگام برنامه نویسی رعایت بشوند. تو این مقاله سعی کردم این اصول رو تا حد امکان ساده توضیح بدم. پس تا انتهای این مقاله با من باشید..‏SOLID چیست؟قوانین SOLID شامل 5 قانون طراحی شی گرا میشه که توسط آقای Robert C. Martin یا همون عمو باب معرفی شدند. پیروی از این قوانین باعث میشه برنامه ما قابل فهم تر بشه، تغییر دادنش راحت تر بشه و همینطور نگهداری از برنامه رو هم آسون تر میکنه(و کلی فواید دیگه?). هر حرف از این عبارت بیانگر یک قانون هست.Single-Responsibility PrincipleOpen–Closed PrincipleLiskov Substitution PrincipleInterface Segregation PrincipleDependency Inversion Principleدو تا نکته ریز: مفاهیمی مانند کلاس یا ماژول استفاده شده تو این مقاله تو بیشتر موارد میتونند جای همدیگه استفاده بشوند. یعنی اگر تو تعریف یک قانون از کلاس استفاده شده، همون قانون ممکنه برای ماژول و گاها تابع یا متد هم صادق باشه.مثال هایی که زده شده فقط برای درک بهتر یک قانون هست. پس ممکنه تو یه مثال قانون های دیگه و اصول دیگه کلا نقض بشوند.‏1. Single-Responsibility Principle(SRP)این قانون میگه که هر کلاس فقط باید یک کار مشخص رو انجام بده یا به عبارت دیگه تنها یک دلیل برای تغییر اون کلاس باید وجود داشته باشه.اگر یک کلاس مسئول کار های مختلفی بشه، در صورتی که یک قسمت خاص از اون کلاس رو تغییر بدیم، ممکنه روی کارکرد قسمت های دیگه از اون کلاس تاثیر بذاره(حتی بدون اینکه شما متوجه بشید). پس این قانون احتمال وجود باگ های ناخواسته رو به شدت کم می کنه.برای درک بهتر به تصویر پایین توجه کنید:تو کد بالا ما یک کلاس به نام Service داریم که دو تا کار گرفتن اطلاعات از سرور و ذخیره اون تو دیتابیس رو انجام میده، بنابراین قانون SRP رو نقض میکنه. برا حل این مشکل این کلاس رو باید به دو کلاس مجزا تقسیم کنیم که یکی کار گرفتن اطلاعات از سرور و دیگری ذخیره اطلاعات تو دیتابیس رو بر عهده داشته باشه.‏2. Open–Closed Principle(OCP)این قانون میگه که کلاس های ما باید به گونه ای نوشته بشوند که اگر خواستیم امکان جدیدی به اون اضافه کنیم، مجبور نباشیم اون کلاس رو تغییر بدیم، بلکه با استفاده از روش هایی مثل ارث بری(یا استفاده از اینترفیس ها و ...) بتونیم قابلیت های اون رو گسترش بدیم.در صورتی که با تغییر یک کلاس بخوایم امکانات جدیدی به اون اضافه کنیم، تغییرات ما ممکنه تو کارکرد بخش های دیگه ای که دارند از اون کلاس استفاده می کنند، مشکل ایجاد کنه. با استفاده از این قانون از این گونه مشکلات جلوگیری میشه.نکته: یک استثنا برای این قانون موقعی هست که میخواید یک باگی رو از کلاس برطرف کنید. یعنی اون موقع باید کلاس رو تغییر بدید.برای درک بهتر به تصویر پایین توجه کنید:تو کد بالا ما دو کلاس با نام های House و Car داریم که دارایی یک شخص رو نشون می دهند(برای همین از اینترفیس Property استفاده می کنند). هر کدوم از این دارایی ها یک ارزش مشخصی دارند. کلاسی با نام TotalPropertyValueCalculator هم داریم که مسئول محاسبه جمع دارایی های یک فرده. در صورتی که یک دارایی دیگه تعریف بکنیم، مجبور هستیم کلاس TotalPropertyValueCalculator رو هم تغییر بدیم که مخالف OCP هست. برای حل این مشکل میتونیم از کد زیر استفاده کنیم. تو کد تصحیح شده زیر تابعی با نام calculateValue رو تو اینترفیس Property تعریف کردیم و هر دارایی بر اساس منطق و متغیر های خودش میتونه اون رو override کنه. در صورت اضافه شدن دارایی جدید هم تنها همون کلاس جدید تغییر می کنه. این مثال تنها یکی از روش های نقض این قانون بود و روش های مختلفی برا نقض اش وجود داره.‏3. Liskov Substitution Principle(LSP)این قانون میگه که فرزندان(Child) یک کلاس نباید کارکرد پدر(Parent) خودشون رو نقض کنند و باید امکان استفاده به جای همدیگه ازشون، بدون مشکل فراهم باشه.احتمالا براتون پیش اومده که یک شی از جنس کلاس فرزند رو به عنوان کلاس پدر به توابع دیگه پاس دادید. در صورتی که به این قانون عمل نکنید، ممکنه کارکرد اون تابع با مشکل مواجه بشه. پس موقعی که دارید توابع کلاس پدر رو توسط فرزند اصطلاحا override می کنید، باید حواستون باشه که کارکرد اصلی تابع پدر نقض نشه.برای درک بهتر به تصویر پایین توجه کنید:تو تصویر بالا ما یک کلاس StorageLogger داریم که کارش ذخیره لاگ بصورت یک فایل تو حافظه هست. کلاس دیگه ای به نام PrinterLogger داریم که از StorageLogger ارث بری کرده و متد saveLogInStorage رو هم override کرده. همون طور که تو تصویر مشخصه این متد به گونه ای override شده که کارکرد پدر خودش رو کاملا نقض کرده و کلا ذخیره کردن لاگ تو حافظه رو نادیده گرفته. حالا فرض کنید کلاسی از شما یک شی از جنس StorageLogger میخواد و شما شی از جنس PrinterLogger رو بهش پاس میدید(چون ارث بری اینجا اتفاق افتاده، پس این کار ممکنه). حالا فرض کنید اون کلاس بعد از صدا زدن متد saveLogInStoreage، فایلی که از لاگ ذخیره شده رو به سرور میفرسته. از اونجایی که موقع override کردن ما هیچ فایلی رو ذخیره نکردیم، ممکنه برنامه با مشکل مواجه بشه. برا حل این مشکل میتونیم ارث بری رو به صورت زیر تغییر بدیم:‏4. Interface Segregation Principle(ISP)این قانون میگه کلاسی که داره از یک interface استفاده میکنه، نباید به توابعی از اون interface وابسته باشه که نیازی بهشون نداره.فرض کنید یک interface ده تا تابع داره. اگر کلاسی که داره از اون Interface استفاده می کنه، فقط به دو تاش نیاز داشته باشه، مجبوره هشت تا تابع دیگه رو به اجبار پیاده سازی کنه(و یا حتی در صورت پیاده سازی اشتباه و یا خالی گذاشتن بدنه، ممکنه باعث باگ های ناخواسته بشه). پس interface ها رو برای کارکرد های مختلف در حد معقول کوچیک در نظر بگیرید.برای درک بهتر به تصویر پایین توجه کنید:این مثال تا حدودی شبیه api های داخلی جاواست. دو تا کلاس با نام FileReader(مسئول خوندن اطلاعات از یک فایل) و FileWriter(مسئول نوشتن اطلاعات تو فایل) داریم. اینترفیس ای به نام Stream هم داریم که نشون دهنده عملیات های خوندن و نوشتن و آزاد کردن منابع هست. از اون جایی که FileReader مسئول خوندن اطلاعات از فایل هست، به متد write نیازی نداره و پیاده سازی ای براش تعریف نشده. از اون طرف کلاس FileWriter هم به متد read نیازی نداره. بنابراین اصل ISP نقض شده. برا حل این مشکل میتونیم از کد زیر استفاده بکنیم که اومدیم به ازای کارکرد های مختلف اینترفیس های کوچکتر و واضح تری تعریف کردیم.‏5. Dependency Inversion Principle(DIP)این قانون به طور خلاصه میگه که باید به abstraction ها(مثلا Interface ها) وابسته باشید نه پیاده سازی ها. یعنی ارتباط شما با کلاس ها یا ماژول های دیگه باید از طریق abstraction ها باشه نه پیاده سازی های خاص.در اصل این قانون 2 تا اصل رو عنوان میکنه که سعی کردم خلاصه اش رو براتون بنویسم. وابسته بودن به abstraction ها به جای جزئیات، باعث میشه به راحتی بتونیم رفتار یک ماژول رو بدون تغییر دادن کد اون بخش عوض کنیم. مثلا به جای اینکه به یک پرینتر با مدل خاص وابسته باشید، به هر چیزی که میتونه عمل پرینت گرفتن رو انجام بده، وابسته باشید. این شیوه وضعیت وابستگی رو تو برنامه شما بهبود میده.برای درک بهتر به تصویر پایین توجه کنید:تو تصویر بالا دو کلاس با نام های ReleaseLogger(مسئول ذخیره و ارسال لاگ به سرور در نسخه ریلیز) و DebugLogger(مسئول چاپ کردن لاگ رو صفحه تو نسخه دیباگ ) داریم. اینترفیس ای هم با نام Logger داریم که این دو کلاس اون رو پیاده کردند. بر اساس قانون DIP، اگر میخواید وابستگی داشته باشید، باید به اینترفیس Logger وابسته باشید نه یکی از کلاس هایی که اون رو پیاده سازی کردن مثل DebugLogger یا ReleaseLogger. این باعث میشه  به راحتی بتونید رفتار کلاس ها رو بدون تغییر دادن اون ها عوض کنید.سخن پایانیتو این مقاله سعی کردم تا حد امکان مطالب رو بصورت واضح و اون طور که درک کردم، توضیح بدم. منتها هیچ چیزی رو نمیشه بهش مسلط شد مگر با تمرین زیاد و البته گذشت زمان. پس پیشنهاد می کنم دست به کد شید و مثال های خودتون از این قوانین رو برا خودتون بنویسید و به مزایا و معایب اش فکر کنید. اگر نظر یا انتقادی داشتید یا ایرادی تو مقاله بود، خیلی خوشحال میشم باهام تو کامنت ها در میون بذارید.ارادتمند شما، هادی درتاج</description>
                <category>هادی درتاج</category>
                <author>هادی درتاج</author>
                <pubDate>Fri, 26 Nov 2021 22:41:37 +0330</pubDate>
            </item>
                    <item>
                <title>تفاوت عملگر &amp; و &amp;&amp; در جاوا</title>
                <link>https://virgool.io/CodeLovers/%D8%AA%D9%81%D8%A7%D9%88%D8%AA-%D8%B9%D9%85%D9%84%DA%AF%D8%B1-&amp;-%D9%88-&amp;&amp;-%D8%AF%D8%B1-%D8%AC%D8%A7%D9%88%D8%A7-epgpccu7pn5x</link>
                <description>به نام تنها برنامه نویس هستیدیروز نصفه شبی یهو به سرم زد که تفاوت دو تا عملگر(operator) &amp; و &amp;&amp; رو تو جاوا یه بررسی عملی بکنم. بعد اینکه فهمیدم گفتم یه مقاله حتی کوتاه در موردش بنویسم شاید به درد کسی خورد.اول یه توضیح سریع در مورد عملگر و عملوند(operand) رو با مثال برا کسایی که نمی دونند بگم. عبارت 2*3 در نظر بگیرید. اینجا 2 و 3 عملوند حساب می شن و * هم عملگر(حوصله نداشتم تعریفش اش بچینم). تو زمینه برنامه نویسی هم مثلا وقتی میگیم a&amp;b اینجا درحقیقت a و b عملوند حساب میشن و &amp;&amp; هم عملگر.بگذریم..بریم سراغ مقایسه. دو تا عملگر &amp;&amp; و &amp; رو از چند لحاظ میشه بررسی کرد:عملگر &amp; میتونه با اعداد و boolean ها مورد استفاده قرار بگیره ولی عملگر &amp;&amp; فقط میتونه با boolean ها استفاده بشه.int a = 9;
int b = 7;
System.out.println(a &amp; b);
System.out.println((a&gt;2) &amp; (b&lt;5));
.....
System.out.println(a &amp;&amp; b); //compile error: Operator &#039;&amp;&amp;&#039; cannot be applied to &#039;int&#039;, &#039;int&#039;
System.out.println((a&gt;2) &amp;&amp; (b&lt;5)); در رابطه با boolean ها، تو عملگر &amp; ابتدا دو عملوند مقدارشون ارزیابی میشه و بعد AND میشن در صورتی که تو عملگر &amp;&amp; اگر مقدار عبارت سمت چپی false بشه دیگه عبارت سمت راستی ارزیابی نمیشه و نتیجه هم false میشه. String name = null;
System.out.println(name != null &amp; !name.isEmpty()); //runtime exception: java.lang.NullPointerExceptionخروجی کد بالا یک اکسپشن از نوع NullPointerException هست. در صورتی که خروجی کد پایین برابر false هست و خطایی رخ نمیده:String name = null;
System.out.println(name != null &amp;&amp; !name.isEmpty());عملگر &amp;&amp; یک عملگر منطقی هست در صورتی که عملگر &amp; یک عملگر بیتی هست، به این معنی که میاد تک تک بیت های عملوند هاش رو با هم دیگه AND می کنه و جواب اون رو تو خروجی نهایی اضافه می کنه. وقتی دو تا بیت با هم دیگه AND میشن، تنها موقعی جواب یک میشه که هر دوشون 1 باشند در غیر اینصورت نتیجه 0 میشه. به مثال زیر دقت کنید:System.out.println(9&amp;7);چیزی که تو خروجی چاپ میشه برای کد بالا برابر عدد 1 هست. به دلیل زیر:reason:
9 =&gt; 1001
7 =&gt; 0111
  =&gt; 0001همون طور که می بینید عدد 9 در مبنای باینری برابر 1001 و عدد 7 برابر 0111 میشه. وقتی تک تک بیت های این دو عدد نظیر به نظیر با هم دیگه AND میشن، عدد حاصل برابر 0001 میشه که در مبنای decimal(همون ده دهی خودمون) برابر 1 میشه.امیدوارم مفید واقع بشه.</description>
                <category>هادی درتاج</category>
                <author>هادی درتاج</author>
                <pubDate>Thu, 31 Dec 2020 13:06:04 +0330</pubDate>
            </item>
                    <item>
                <title>تفاوت data class و normal class در کاتلین</title>
                <link>https://virgool.io/coderlife/%D8%AA%D9%81%D8%A7%D9%88%D8%AA-data-class-%D9%88-normal-class-%D8%AF%D8%B1-%DA%A9%D8%A7%D8%AA%D9%84%DB%8C%D9%86-uh0voqkqqgzf</link>
                <description>بسم الله الرحمن الرحیمکلاس داده(data class) تو کاتلین به کلاس ای گفته می شه که وظیفه اصلی اون نگه داشتن داده ها یا اطلاعات است. بنابراین موقعی که قصد ایجاد کلاسی رو دارید که فقط میخواید اطلاعاتی رو داخلش نگه دارید از data class استفاده کنید. ولی قبل اش باید بدونید که زبان برنامه نویسی کاتلین بین کلاس های داده و کلاس معمولی چه تفاوتی قائل می شه.تفاوت کلاس های داده و کلاس های معمولیبرای اینکه تفاوت این دو نوع کلاس رو بهتون نشون بدم دو کلاس با نام های NormalClassUser(که نقش کلاس معمولی من رو به عهده داره) و DataClassUser(که نقش کلاس داده من رو به عهده داره)  ساختم. این دو کلاس دارای دو property یکسان با نام های name و age هستند.1) نحوه اعلاناولین تفاوت در نحوه تعریف کلاس داده و کلاس معمولی است. کلاس های معمولی با کلیدواژه class و کلاس های داده با کلیدواژه data class تعریف می شوند. مثال:class NormalClassUser (val name : String, val age : Int) // کلاس معمولی
- - - - - - -
data class DataClassUser(val name: String, val age: Int) // کلاس داده
2) تابع ()toStringتفاوت بعدی در مقداری است که متد ()toString برای هر یک بر می گرداند. به کد زیر توجه کنید:fun main() {
    val dataClassUser = DataClassUser(&amp;quothadi&amp;quot, 21)
    val normalClassUser = NormalClassUser(&amp;quothadi&amp;quot, 21)

    println(dataClassUser.toString())
    println(normalClassUser.toString())
}تو قطعه کد بالا من اومدم دو نوع شی از جنس  DataClassUser و NormalClassUser ایجاد کردم و مقادیر hadi و 21 رو تو constructor بهشون پاس دادم. بعدش اومدم متد ()toString رو ابتدا برای شی dataClassUser و بعدش برای شی normalClassUser صدا زدم و خروجی این متد ها رو چاپ کردم. اگر قطعه کد بالا رو اجرا کنیم خروجی ای مشابه زیر رو خواهیم دید:DataClassUser(name=hadi, age=21)
com.example.myapplication.NormalClassUser@610455d6همون طور که می بینید متد ()toString وقتی روی یک کلاس داده فراخوانی میشه، به جای اینکه آدرس اون شی رو تو حافظه بهمون بده، مقادیر داخل اون شی رو برامون برمیگردونه. ولی هنگامی که روی یک کلاس معمولی فراخوانی میشه آدرس اون شی رو در حافظه برامون برمیگردونه.3) تابع ()copyهنگامی که از کلاس داده استفاده می کنیم، کاتلین به صورت اتوماتیک یک تابع به نام ()copy رو برامون تولید می کنه. کار اصلی این تابع ایجاد یک کپی از شی کلاس داده است(کار مشابه دیزاین پترن Prototype رو انجام میده). برا اینکه متوجه این مطلب بشید به قطعه کد زیر دقت کنید:fun main() {
    val dataClassUser = DataClassUser(&amp;quothadi&amp;quot, 21)
    val copy = dataClassUser.copy()
    println(copy.toString())
}تو کد بالا من اومدم و متد copy رو برای شی dataClassUser صدا زدم و نتیجه اش رو داخل متغیر copy ریختم. و بعد مقدار برگشتی حاصل از صدا زدن تابع ()toString روی شی copy رو چاپ کردم. خروجی به صورت زیر است:DataClassUser(name=hadi, age=21)همون طور که می بینید مقادیر داخل شی copy دقیقا برابر مقادیر داخل شی dataClassUser هست. لازم به ذکره که این دو شی از همدیگر مستقل هستند و آدرس حافظه متفاوتی دارند. بنابراین تغییرات هر یک روی دیگری تاثیر نخواهد گذاشت.البته این همه ی کار تابع ()copy نیست. بلکه ما میتونیم هنگامی که این تابع رو صدا می زنیم مقادیری رو نیز روی شی جدید ست کنیم. برای درک این مطلب به قطعه کد زیر توجه کنید:fun main() {
    val dataClassUser = DataClassUser(&amp;quothadi&amp;quot, 21)
    val copy = dataClassUser.copy(age = 40)
    println(copy.toString())
}این قطعه کد خروجی زیر رو چاپ می کنه:DataClassUser(name=hadi, age=40)همون طور که می بینید مقدار name در شی copy دقیقا برابر مقدار name داخل شی dataClassUser است ولی age تغییر کرده است، چرا که هنگام صدا زدن تابع ()copy خودمان آن را عوض کردیم.این تابع به صورت خودکار برای کلاس های معمولی تولید نمی شود.4) توابع ()componentXهنگام استفاده از کلاس های داده، به صورت خودکار به تعداد property هایی که داخل کلاس داده مون داریم توابع ()component1(), component2 و ... تولید میشه. به این صورت که ()component1 مقدار اولین property داخل کلاس داده، ()component2 مقدار دومین property و به همین صورت ()componenX مقدار x امین property کلاس داده رو برمیگردونه. برای درک این مطلب به کد زیر دقت کنید:fun main() {
    val dataClassUser = DataClassUser(&amp;quothadi&amp;quot, 21)
    println(dataClassUser.component1())
    println(dataClassUser.component2())
}خروجی کد بالا به صورت زیر خواهد بود:hadi
21همون طور که می بینید تابع ()component1 مقدار hadi رو برگردونده و تابع ()component2 مقدار 21 رو که مطابق چیزی هست که بالا تر اشاره کردم.قابلیت جالبی تو کاتلین هست به اسم Destructuring Declarations که به ما این امکان رو میده که یک کلاس رو به یک یا چند متغیر بشکنیم. اگر برای شی ای توابع ()componentX تولید بشه، می تونیم اون رو به متغیر هایی بشکنیم. به این کد توجه کنید:fun main() {
    val dataClassUser = DataClassUser(&amp;quothadi&amp;quot, 21)
    val (x, y) = dataClassUser
    println(&amp;quotx: $x y: $y&amp;quot)
}تو این کد من دو متغیر x و y داخل پرانتر تعریف کردم و مقدار اون ها رو برابر کلاس داده خودم قرار دادم. خروجی کد بالا به صورت زیر است:x: hadi y: 21همون طور که می بینید مقدار متغیر x برابر ویژگی name و مقدار y برابر ویژگی y از شی dataClassUser شدند. یعنی مقادیر property های موجود در شی dataClassUser نظیر به نظیر داخل متغیر های x و y ریخته شدند.مشابه این کار رو اگر با map ها کار کرده باشید احتمالا دیدید. به طور مثال:fun main() {
    val map = mapOf(&amp;quotname&amp;quot to 21, &amp;quotmehdi&amp;quot to 24)
    for((name, age) in map){
        println(&amp;quotname: $name age: $age&amp;quot)
    }
}تو قطعه کد بالا ابتدا یک map تعریف کردم که رشته هایی رو به عدد هایی map می کنه. بعد گفتم به ازای هر name و age از داخل این map بیا و name و age رو چاپ کن. همون طور که میدونید هر map مجموعه ای از Map.Entry ها رو داخل خودش نگه می داره. بنابراین name و age باید به مقادیر داخل یک Map.Entry اشاره کنند. نحوه تعریف Map.Entry به صورت زیر است:public interface Entry&lt;out K, out V&gt; {
    public val key: K
    public val value: V
}همون طور که می بینید دو property به نام های key و value داره. دلیل اینکه ما تونستیم از قابلیت Destructuring Declarations برای Map.Entry های موجود در map مون استفاده کنیم این بود که توابع componentX برای این interface تولید میشه.5) تابع ()equals و ()hashCodeتابع ()equals که در کلاس Any وجود دارد، به منظور مقایسه مقادیر داخل دو شی به کار می رود. تو کاتلین اگر دو شی رو به صورت a == b مقایسه کنیم، مقدار حاصل از این مقایسه برابر حاصل عبارت a.equals(b) خواهد بود(کارکرد عملگر == تو کاتلین با جاوا فرق داره). پیاده سازی پیش فرض تابع ()equals چک می کند که آیا دو شی به یک شی اشاره می کنند یا خیر، به عبارت دیگر چک می کند که آیا مکان دو شی در حافظه یکی است یا نه. اگر خواستیم که این پیاده سازی را تصحیح کنیم و مثلا بگوییم که اگر مقادیر داخل دو شی یکی بود، true بشود و در غیر اینصورت false، در کلاس های معمولی مجبوریم که این تابع را override کنیم.اما در کلاس های داده، کاتلین به صورت خودکار دو تابع ()hashCode و ()equals را پیاده سازی می کند. در پیاده سازی خودکار تابع ()equals، کاتلین تک تک عناصر دو کلاس داده را(اگر از یک جنس بوند) بررسی می کند و اگر همه ی آن ها برابر بودند، مقدار حاصل از فراخوانی تابع equals برابر true خواهد شد. در غیر اینصورت false برگردانده خواهد شد. به کد زیر توجه کنید:fun main() {
    val dataClassUser1 = DataClassUser(&amp;quothadi&amp;quot, 21)
    val dataClassUser2 = DataClassUser(&amp;quothadi&amp;quot, 21)

    val normalClassUser1 = NormalClassUser(&amp;quothadi&amp;quot, 21)
    val normalClassUser2 = NormalClassUser(&amp;quothadi&amp;quot, 21)

    println(&amp;quotdataClassUser1==dataClassUser2: ${dataClassUser1 == dataClassUser2}&amp;quot)
    println(&amp;quotnormalClassUser1==normalClassUser2: ${normalClassUser1 == normalClassUser2}&amp;quot)
}نتیجه قطعه کد بالا به صورت زیر خواهد بود:dataClassUser1==dataClassUser2: true
normalClassUser1==normalClassUser2: falseاگر به کد decompile شده کلاس DataClassUser نگاهی بیندازیم می توانیم پیاده سازی تابع equals را ببینیم.public boolean equals(@Nullable Object var1) {
   if (this != var1) {
      if (var1 instanceof DataClassUser) {
         DataClassUser var2 = (DataClassUser)var1;
         if (Intrinsics.areEqual(this.name, var2.name) &amp;&amp; this.age == var2.age) {
            return true;
         }
      }

      return false;
   } else {
      return true;
   }
}
سخن آخرخب اولین مقاله من در ویرگول به پایان رسید. خوشحال میشم اگر این مقاله براتون مفید بود لایک کنید و همچنین اگر انتقاد یا پیشنهادی جهت بالابردن کیفیت مقاله های آتی(انشاءالله) داشتید با من در میون بذارید.</description>
                <category>هادی درتاج</category>
                <author>هادی درتاج</author>
                <pubDate>Wed, 17 Jun 2020 17:26:01 +0430</pubDate>
            </item>
            </channel>
</rss>