
97. آیا هنگام بازگرداندن () برابری، قوانینی اعمال می شود؟
هنگام نادیده گرفتن متد ()quals، باید قوانین زیر را رعایت کنید:-
بازتاب - برای هر مقدار x ، x.equals(x) همیشه باید true را برگرداند (که x != null ).
-
تقارن - برای هر مقدار x و y ، x.equals(y) فقط باید true را برگرداند اگر y.equals(x) true را برگرداند .
-
گذر - برای هر مقدار x ، y و z ، اگر x.equals(y) true و y.equals(z) نیز true را برمی گرداند ، آنگاه x.equals(z) باید true را برگرداند .
-
سازگاری - برای هر مقدار x و y ، فراخوانی مکرر x.equals(y) همیشه همان مقدار را برمیگرداند تا زمانی که فیلدهای مورد استفاده برای مقایسه دو شی بین هر فراخوانی تغییر نکرده باشند.
-
مقایسه null - برای هر مقدار x ، فراخوانی x.equals(null) باید false را برگرداند .
98. اگر برابر () و hashCode() را نادیده نگیرید چه اتفاقی می افتد؟
در این حالت، hashCode() عددی را برمیگرداند که بر اساس آدرس سلول حافظه که شی در آن ذخیره میشود، تولید شده است. به عبارت دیگر، زمانی که متد ()hashCode اصلی بر روی دو شی با فیلدهای کاملاً یکسان فراخوانی شود، نتیجه متفاوت خواهد بود (زیرا در مکانهای مختلف حافظه ذخیره میشوند). متد () quals original مراجع را با هم مقایسه می کند، یعنی نشان می دهد که آیا مراجع به یک شی اشاره می کنند یا خیر. به عبارت دیگر، مقایسه از عملگر == استفاده می کند، و همیشه برای اشیاء مختلف false برمی گرداند ، حتی زمانی که فیلدهای آنها یکسان باشد. true فقط هنگام مقایسه ارجاعات به یک شی بازگردانده می شود. گاهی اوقات منطقی است که این روش ها را نادیده نگیرید. به عنوان مثال، شما می خواهید همه اشیاء یک کلاس خاص منحصر به فرد باشند - نادیده گرفتن این روش ها تنها می تواند ضمانت موجود کدهای هش منحصر به فرد را از بین ببرد. نکته مهم این است که تفاوتهای ظریف این روشها را درک کنید، خواه نادیده گرفته شوند یا نه، و از هر رویکردی که موقعیت میخواهد استفاده کنید.99. چرا شرط تقارن فقط در صورتی برآورده می شود که x.equals(y) درست برمی گردد؟
این سوال کمی عجیب است. اگر شی A برابر با شی B باشد، شی B برابر با شی A است. این عقل سلیم است.100. برخورد HashCode چیست؟ چطور با این کنار میای؟
برخورد HashCode زمانی رخ می دهد که دو شی مختلف دارای HashCode یکسان باشند . چطور ممکن است؟ خوب، کد هش به یک عدد صحیح نگاشت می شود که دارای محدوده ای از -2147483648 تا 2147483647 است. یعنی می تواند یکی از تقریباً 4 میلیارد عدد صحیح مختلف باشد. این محدوده بزرگ است اما بی نهایت نیست. این بدان معناست که شرایطی وجود دارد که دو شی کاملاً متفاوت ممکن است کد هش یکسانی داشته باشند. بسیار بعید است، اما ممکن است. یک تابع درهم سازی ضعیف می تواند کدهای هش یکسان را با برگرداندن اعداد در محدوده کوچکی تکرار کند و در نتیجه احتمال برخورد را افزایش دهد. برای کاهش برخوردها، باید روش HashCode را پیاده سازی کنید که به طور یکنواخت مقادیر را پخش کند و احتمال تکرار مقادیر را به حداقل برساند.101. اگر مقدار عنصر شرکت کننده در قرارداد hashCode تغییر کند چه اتفاقی می افتد؟
اگر عنصری که در محاسبه کد هش دخیل است تغییر کند، کد هش شی باید تغییر کند (اگر عملکرد هش خوب باشد). به همین دلیل است که باید از اشیاء تغییرناپذیر به عنوان کلید در HashMap استفاده کنید ، زیرا وضعیت داخلی آنها (فیلدها) پس از ایجاد قابل تغییر نیست. و نتیجه این است که کد هش آنها پس از ایجاد تغییر می کند. اگر از یک شیء قابل تغییر به عنوان کلید استفاده می کنید، وقتی فیلدهای شی تغییر می کند، کد هش آن تغییر می کند و می توانید جفت کلید-مقدار مربوطه را در HashMap از دست بدهید . پس از همه، در سطل مرتبط با کد هش اصلی ذخیره می شود، اما پس از تغییر شی، آن را در یک سطل دیگر جستجو خواهید کرد.102. متدهای برابر () و hashCode() را برای یک کلاس Student که دارای فیلدهای String name و int age است بنویسید.
public class Student {
int age;
String name;
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || this.getClass() != o.getClass()) {
return false;
}
final Student student = (Student) o;
if (this.age != student.age) {
return false;
}
return this.name != null ? this.name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = this.age;
result = 31 * result + (this.name != null ? this.name.hashCode() : 0);
return result;
}
}
برابر ():
-
ابتدا، ما به طور مستقیم مراجع را با هم مقایسه می کنیم، زیرا اگر مراجع به یک شی اشاره کنند، ادامه بررسی برابری چه فایده ای دارد؟ ما قبلاً می دانیم که نتیجه درست خواهد بود .
-
ما null را بررسی می کنیم و اینکه آیا انواع کلاس ها یکسان هستند، زیرا اگر پارامتر null یا از نوع دیگری باشد، آنگاه اشیاء نمی توانند برابر باشند و نتیجه باید false باشد .
-
ما پارامتر را به همان نوع می فرستیم (بالاخره، اگر یک شی از نوع والد باشد چه می شود).
-
ما فیلدهای اولیه را با هم مقایسه می کنیم (مقایسه با استفاده از =! کافی است). اگر برابر نباشند، false را برمی گردانیم .
-
فیلد غیر ابتدایی را بررسی می کنیم تا ببینیم که آیا null است و از متد برابر استفاده می کنیم ( کلاس String روش را لغو می کند، بنابراین مقایسه را به درستی انجام می دهد). اگر هر دو فیلد تهی باشند یا برابر با true باشد ، بررسی را متوقف می کنیم و متد true را برمی گرداند .
-
مقدار اولیه کد هش را برابر با مقدار فیلد سن شی قرار می دهیم .
-
کد هش فعلی را در 31 ضرب می کنیم (برای گسترش بیشتر در مقادیر) و سپس کد هش فیلد String غیر ابتدایی را اضافه می کنیم (اگر تهی نباشد).
-
نتیجه را برمی گردانیم.
-
نادیده گرفتن متد به این روش به این معنی است که اشیاء با همان نام و مقادیر int همیشه همان کد هش را برمیگردانند.
103. تفاوت بین استفاده از "if (obj instanceof Student)" و "if (getClass() == obj.getClass())" چیست؟
بیایید نگاهی به عملکرد هر عبارت بیندازیم:-
instanceof بررسی می کند که آیا مرجع شی در سمت چپ نمونه ای از نوع سمت راست است یا یکی از انواع فرعی آن.
-
"getClass() == ..." یکسان بودن انواع را بررسی می کند.
104. توضیح مختصری از متد ()clone ارائه دهید.
متد ()clone متعلق به کلاس Object است . هدف آن ایجاد و بازگرداندن یک کلون (کپی) از شی فعلی است.
Student implements Cloneable
و خود متد clone() را لغو کنید:
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
به هر حال، در کلاس Object محافظت می شود ، یعنی فقط در کلاس Student قابل مشاهده است و برای کلاس های خارجی قابل مشاهده نیست.
105. در مورد متد ()clone و متغیرهای مرجع در یک شی، چه ملاحظات خاصی را باید در نظر داشته باشید؟
هنگامی که اشیاء کلون می شوند، فقط مقادیر اولیه و مقدار ارجاعات شیء کپی می شوند. این بدان معنی است که اگر یک شی دارای یک فیلد باشد که به یک شی دیگر ارجاع می دهد، آنگاه فقط مرجع کلون می شود - این شی مرجع دیگر کلون نمی شود. این همان چیزی است که به آن کپی کم عمق می گویند. بنابراین، اگر به یک کپی کامل نیاز دارید، که در آن هر شی تودرتو کلون شده است، چه؟ چگونه مطمئن میشوید که اینها کپیهای صرف از مراجع نیستند، بلکه کپیهای کاملی از اشیاء متمایز هستند که آدرسهای حافظه متمایز را در پشته اشغال میکنند؟ در واقع، همه چیز بسیار ساده است - برای هر کلاسی که به صورت داخلی ارجاع داده می شود، باید متد ()clone را لغو کنید و رابط نشانگر Cloneable را اضافه کنید. هنگامی که این کار را انجام دادید، عملیات کلون ارجاعات را به اشیاء موجود کپی نمی کند، بلکه در عوض اشیاء ارجاع شده را کپی می کند، زیرا اکنون آنها نیز توانایی کپی کردن خود را دارند.استثناها
106. تفاوت بین خطا و استثنا چیست؟
استثناها، و همچنین خطاها، زیر کلاس های Throwable هستند . با این حال، آنها تفاوت های خود را دارند. خطا نشان دهنده مشکلی است که عمدتاً به دلیل کمبود منابع سیستم رخ می دهد. و برنامه ما نباید این نوع مشکلات را ببیند. نمونه هایی از این خطاها شامل خرابی سیستم و خطای خارج از حافظه است. خطاها اکثراً در زمان اجرا رخ می دهند، زیرا تیک آن ها غیرقابل بررسی است.
107. تفاوت بین علامت زده، بدون علامت، استثنا، پرتاب و پرتاب چیست؟
همانطور که قبلاً گفتم، یک استثنا یک خطای زمان اجرا یا زمان کامپایل است که در کد نوشته شده توسط توسعه دهنده (به دلیل شرایط غیرعادی) رخ می دهد. Checked چیزی است که ما آن را استثنا می نامیم که یک روش باید همیشه با استفاده از مکانیسم try-catch یا بازگرداندن به روش فراخوانی آن را مدیریت کند. کلمه کلیدی throws در هدر متد برای نشان دادن استثناهایی که روش ممکن است ایجاد کند استفاده می شود. به عبارت دیگر، مکانیزمی برای پرتاب استثناها به روش فراخوانی در اختیار ما قرار می دهد. استثناهای بدون علامت نیازی به رسیدگی ندارند. آنها کمتر قابل پیش بینی هستند و احتمال کمتری دارند. گفته می شود، اگر بخواهید می توانید آنها را مدیریت کنید. ما هنگام پرتاب دستی یک استثنا استفاده می کنیم ، به عنوان مثال:
throw new Exception();
108. سلسله مراتب استثنا چیست؟
سلسله مراتب استثنا بسیار گسترده است. در اینجا چیزهای زیادی برای توصیف کافی وجود دارد. بنابراین، در عوض، ما فقط شاخههای کلیدی آن را در نظر میگیریم:
- خطاها - مشکلات مهم، بررسی نشده.
- استثناها - استثناهایی که قابل بررسی هستند.
109. استثناهای چک شده و تیک نشده چیست؟
همانطور که قبلاً گفتم:-
استثناهای علامت زده شده استثناهایی هستند که باید به نحوی آنها را مدیریت کنید. یعنی یا باید آنها را در یک بلوک try-catch مدیریت کنید یا آنها را به روش بالا پرتاب کنید. برای انجام این کار، پس از فهرست کردن آرگومان های متد در امضای متد، از throws <exception type> استفاده کنید تا نشان دهید که متد می تواند آن استثنا را ایجاد کند. این تا حدودی شبیه یک هشدار است که متد فراخوانی را متذکر میشود که باید مسئولیت رسیدگی به آن استثنا را بر عهده بگیرد.
-
استثناهای چک نشده نیازی به رسیدگی ندارند، زیرا در زمان کامپایل بررسی نمی شوند و معمولاً غیرقابل پیش بینی هستند. تفاوت اصلی آنها با استثناهای بررسی شده این است که مدیریت آنها با استفاده از یک بلوک try-catch یا با پرتاب مجدد اختیاری است و نه اجباری.
101. مثالی بنویسید که در آن از بلوک try-catch برای گرفتن و رسیدگی به یک استثنا استفاده می کنید.
try{ // Start of the try-catch block
throw new Exception(); // Manually throw an exception
} catch (Exception e) { // Exceptions of this type and its subtypes will be caught
System.out.println("Oops! Something went wrong =("); // Display the exception
}
102. مثالی بنویسید که در آن استثناهای سفارشی خود را پیدا کرده و مدیریت کنید.
ابتدا، بیایید کلاس استثنای خودمان را بنویسیم که Exception را به ارث می برد و سازنده آن را که یک پیام خطا را به عنوان آرگومان می گیرد، لغو کنیم:
public class CustomException extends Exception {
public CustomException(final String message) {
super(message);
}
}
در مرحله بعد ما به صورت دستی یکی را پرتاب می کنیم و همانطور که در مثال سوال قبلی انجام دادیم آن را می گیریم:
try{
throw new CustomException("Oops! Something went wrong =(");
} catch (CustomException e) {
System.out.println(e.getMessage());
}
یک بار دیگر، زمانی که کد خود را اجرا می کنیم، خروجی زیر را دریافت می کنیم:

GO TO FULL VERSION