97. האם מוטלים תנאים להגדרה מחדש של הסכם בעת הגדרה מחדש של Equals?
שיטת העקיפה equals() חייבת לעמוד בתנאים (הכללים) הבאים:-
רפלקסיביות - עבור כל ערך 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) תמיד תחזיר את הערך של הקריאה הקודמת לשיטה זו, בתנאי שהשדות ששימשו להשוואה בין שני האובייקטים לא השתנו בין הקריאות .
-
comparison null - עבור כל ערך x, קריאה ל- x.equals(null) תחזיר false .
98. מה קורה אם לא תעקוף את Equals ואת HashCode?
במקרה זה, hashCode() יחזיר מספר שנוצר על סמך מיקום הזיכרון שבו מאוחסן האובייקט הנתון. כלומר, שני אובייקטים בעלי אותם שדות בדיוק יקבלו ערכים שונים בעת קריאה ל- hashCode() שאינו נדחק (אחרי הכל, הם מאוחסנים במיקומי זיכרון שונים). ה-Unoverridden equals() משווה הפניות כדי לראות אם הן מצביעות על אותו אובייקט או לא. כלומר, ההשוואה מתבצעת דרך == , ובמקרה של אובייקטים עם אותם שדות היא תמיד תחזיר false . נכון יהיה רק כאשר משווים הפניות לאותו אובייקט. לפעמים יש היגיון בכך שלא לעקוף את השיטות הללו. לדוגמה, אתה רוצה שכל האובייקטים של מחלקה מסוימת יהיו ייחודיים ועקיפה של שיטות אלה רק תקלקל את ההיגיון של הייחודיות. העיקר הוא להבין את הניואנסים של שיטות דחוקות ושאינן מבוטלות ולהשתמש בשתי הגישות בהתאם למצב.99. מדוע סימטריה נכונה רק אם x.equals(y) מחזירה true?
שאלה קצת מוזרה. אם אובייקט A שווה לאובייקט B, אז אובייקט B שווה לאובייקט A. אם B אינו שווה לאובייקט A, אז איך ייתכן ההפך? זה היגיון פשוט.100. מהי התנגשות ב-HashCode? איך להתמודד עם זה?
התנגשות hashCode היא מצב שבו לשני אובייקטים שונים יש ערך hashCode זהה . איך זה אפשרי? העובדה היא שקוד hash ממופה לסוג Integer , שבתורו יש טווח שבין -2147483648 ל-2147483647, כלומר כ-4 מיליארד מספרים שלמים שונים. הטווח הזה הוא עצום, עם זאת, הוא לא אינסופי. לכן, מצבים אפשריים כאשר לשני אובייקטים שונים לחלוטין יש קוד hash זהה. זה מאוד לא סביר, אבל אפשרי. פונקציית Hash מיושמת בצורה גרועה יכולה גם להגביר את התדירות של קודי Hash זהים, שיחזירו למשל מספרים בטווח קטן, מה שיגדיל את הסיכוי להתנגשויות. כדי להילחם בהתנגשות, יש צורך ביישום טוב של שיטת ה-hashCode כך שהתפשטות הערכים תהיה מקסימלית והסיכוי לחזור על ערכים מינימלי.101. מה קורה אם אלמנט המשתתף בחוזה HashCode משנה את ערכו?
אם אלמנט שמעורב בחישוב קוד ה-hash שונה, אזי ישתנה קוד ה-hash של האובייקט עצמו (אם פונקציית ה-hash טובה). לכן, ב- HashMap מומלץ להשתמש באובייקטים בלתי ניתנים לשינוי (בלתי ניתנים לשינוי) כמפתח, מכיוון שלא ניתן לשנות את המצב הפנימי (שדות) שלהם לאחר היצירה. בהתאם, גם קוד ה-hash שלהם אינו מומר לאחר היצירה. אם אתה משתמש באובייקט שניתן לשינוי כמפתח, אז כאשר אתה משנה את השדות של אובייקט זה, קוד ה-hash שלו ישתנה, וכתוצאה מכך, אתה יכול לאבד את הצמד הזה ב- HashMap . אחרי הכל, הוא יישמר ב-bucket של קוד ה-hash המקורי, ולאחר שינוי זה יבוצע חיפוש בדלי אחר.102. כתוב שיטות Equals ו-HashCode לכיתת הסטודנט, המורכבת משדות שם מחרוזת ושדות גיל int
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 .
-
יציקת אובייקט הארגומנט לסוג אחד (במקרה שהיה אובייקט מסוג האב).
-
השוואה של שדה מחלקה פרימיטיבי (בכל זאת, השוואה דרך =! מספיקה בשביל זה ), אם השדה לא שווה - שקר .
-
בדיקת שדה לא פרימיטיבי עבור null ושווה ( במחרוזת השיטה מוחקת ותשוווה נכון), אם שני השדות הם null או שווים , אז הסימון מסתיים והשיטה מחזירה true .
-
הגדרת ערך קוד ה-hash הראשוני לפרימיטיבי הגיל של האובייקט .
-
הכפלת קוד ה-hash הנוכחי ב-31 (לפיזור גדול יותר) והוספת אליו את קוד ה-hash של שדה מחרוזת לא פרימיטיבי (אם הוא אינו null).
-
מחזיר את התוצאה.
-
כתוצאה מעקיפה זו של קוד ה-hash, אובייקטים בעלי אותו שם וערכי int יחזירו תמיד את אותו הערך.
103. מה ההבדל בין שימוש ב- if (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. מה ההבדל בין מסומן לבלתי מסומן, חריג, זריקה, זריקה.
כפי שאמרתי קודם, חריג הוא שגיאה במהלך הפעלת התוכנית ובמהלך הקומפילציה שהתרחשה בקוד שנכתב על ידי המפתח (בגלל מצב לא נורמלי כלשהו). מסומן הוא סוג של חריג שתמיד יש לטפל בו באמצעות מנגנון ה- try-catch או לזרוק אותו לשיטות שלמעלה. Throws משמש בכותרת השיטה כדי לציין חריגים אפשריים שנזרקה על ידי השיטה. כלומר, זהו המנגנון ל"השלכת" חריגים לשיטות לעיל. לא מסומן הוא סוג של חריג שאין צורך לטפל בו ובדרך כלל הוא פחות צפוי וסביר פחות להתרחש. עם זאת, ניתן גם לעבד אותם אם תרצה. Throw משמש בעת זריקת חריגה באופן ידני, לדוגמה:throw new Exception();
108. מהי ההיררכיה של חריגים?
היררכיית החריגים היא מאוד גדולה ונרחבת, אפילו נרחבת מכדי לספר עליה הכל כאן. לכן, נשקול רק את הקישורים המרכזיים שלו: כאן ממש בראש ההיררכיה אנו רואים את המחלקה - Throwable - מחלקה כללית, האב הקדמון של היררכיית החריג, אשר בתורה מחולקת ל:- שגיאה - שגיאות קריטיות שאינן ניתנות לסימון.
- חריגה - חריגים מסומנים.
109. מה זה חריג מסומן ולא מסומן?
כמו שאמרתי קודם:-
מסומנים - חריגים שאתה חייב איכשהו לטפל בהם, כלומר, לעבד אותם ב- try-catch block , או "להעביר" אותם לשיטה שלמעלה. לשם כך, בחתימת השיטה, לאחר פירוט ארגומנטי המתודה, עליך להשתמש במילת המפתח trows <exception type> , אשר מציינת למשתמשי השיטה שהשיטה יכולה לזרוק את החריג הזה (משהו כמו אזהרה) ומעבירה את אחריות לטפל בחריג למשתמשים בשיטה זו.
-
Unchecked - חריגים שאין צורך לטפל בהם, מכיוון שהם אינם נבדקים בזמן ההידור וככלל, הם בלתי צפויים יותר. כלומר, ההבדל העיקרי עם checked הוא שעבורם מנגנוני הנסיון או ההשלכה הללו עובדים אותו הדבר, אבל הם לא חובה.
101. כתבו דוגמה של יירוט וטיפול בחריג בבלוק try-catch של שיטה
try{ // начало блока перехвата
throw new Exception(); // ручной бросок исключения
} catch (Exception e) { // данное исключение и его потомки будут перехватываться
System.out.println("Упс, что-то пошло не так =("); // вывод некоторого исключения в консоль
}
102. כתוב דוגמה לתפיסה וטיפול בחריג באמצעות חריגים משלך
ראשית, בואו נכתוב מחלקה חריגה משלנו, שיורשת מ- Exception ותעקוף את הבנאי שלו בהודעת שגיאה:public class CustomException extends Exception {
public CustomException(final String message) {
super(message);
}
}
ובכן, אז נזרוק אותו ידנית וניירט אותו כמו בשאלה הקודמת:
try{
throw new CustomException("Упс, что-то пошло не так =(");
} catch (CustomException e) {
System.out.println(e.getMessage());
}
ושוב, כאשר תפעיל אותו, תקבל את הפלט הבא לקונסולה:
GO TO FULL VERSION