JavaRush /בלוג Java /Random-HE /ניתוח שאלות ותשובות מראיונות למפתח Java. חלק 7

ניתוח שאלות ותשובות מראיונות למפתח Java. חלק 7

פורסם בקבוצה
היי לכולם! התכנות מלא במלכודות. ואין כמעט נושא שבו לא תמעד ותקבל מהמורות. זה נכון במיוחד למתחילים. הדרך היחידה לצמצם את זה היא ללמוד. בפרט, זה חל על ניתוחים מפורטים של הנושאים הבסיסיים ביותר. היום אני ממשיך לנתח יותר מ-250 שאלות מראיונות מפתח Java, המכסים נושאים בסיסיים היטב. ברצוני לציין שהרשימה מכילה גם כמה שאלות לא סטנדרטיות המאפשרות להסתכל על נושאים נפוצים מזווית אחרת.ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 7 - 1

62. מהי בריכת מיתר ולמה יש צורך בה?

בזיכרון ב-Java (Heap, עליו נדבר בהמשך) יש אזור - String pool , או string pool. זה נועד לאחסן ערכי מחרוזת. במילים אחרות, כאשר אתה יוצר מחרוזת מסוימת, למשל באמצעות מרכאות כפולות:
String str = "Hello world";
מתבצעת בדיקה כדי לראות אם למאגר המיתרים יש את הערך הנתון. אם כן, למשתנה str מוקצה הפניה לערך זה במאגר. אם לא, ייווצר ערך חדש במאגר, והפניה אליו תוקצה למשתנה str . בואו נסתכל על דוגמה:
String firstStr = "Hello world";
String secondStr = "Hello world";
System.out.println(firstStr == secondStr);
true יוצג על המסך . אנו זוכרים ש -== משווה הפניות - כלומר שתי הפניות אלו מתייחסות לאותו ערך ממאגר המחרוזות. זה נעשה על מנת לא לייצר הרבה אובייקטים זהים מסוג String בזיכרון, כי כזכור, String הוא מחלקה בלתי ניתנת לשינוי, ואם יש לנו הרבה הפניות לאותו ערך, אין בזה שום דבר רע. כבר לא יתכן מצב שבו שינוי ערך במקום אחד מוביל לשינויים עבור מספר קישורים אחרים בו זמנית. אבל בכל זאת, אם ניצור מחרוזת באמצעות new :
String str = new String("Hello world");
יווצר אובייקט נפרד בזיכרון שיאחסן את ערך המחרוזת הזה (ולא משנה אם כבר יש לנו ערך כזה במאגר המחרוזות). כאישור:
String firstStr = new String("Hello world");
String secondStr = "Hello world";
String thirdStr = new String("Hello world");
System.out.println(firstStr == secondStr);
System.out.println(firstStr == thirdStr);
נקבל שני ערכים שגויים , מה שאומר שיש לנו כאן שלושה ערכים שונים שמפנים אליהם. למעשה, זו הסיבה שמומלץ ליצור מחרוזות פשוט באמצעות מרכאות כפולות. עם זאת, אתה יכול להוסיף (או לקבל הפניה) ערכים לתוך מאגר מחרוזות בעת יצירת אובייקט באמצעות new . לשם כך, אנו משתמשים בשיטת המחלקה string - intern() . שיטה זו יוצרת בכוח ערך במאגר המחרוזות, או מקבלת קישור אליו אם היא כבר מאוחסנת שם. הנה דוגמה:
String firstStr = new String("Hello world").intern();
String secondStr = "Hello world";
String thirdStr = new String("Hello world").intern();
System.out.println(firstStr == secondStr);
System.out.println(firstStr == thirdStr);
System.out.println(secondStr == thirdStr);
כתוצאה מכך, נקבל שלושה ערכים אמיתיים בקונסולה , מה שאומר שכל שלושת המשתנים מתייחסים לאותה מחרוזת.ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 7 - 2

63. באילו תבניות GOF משתמשים בבריכת המיתרים?

תבנית ה-GOF נראית בבירור בבריכת המיתרים - משקל זבוב , המכונה אחרת מתיישב. אם אתה רואה תבנית נוספת כאן, שתף אותה בתגובות. ובכן, בואו נדבר על התבנית הקלה. קל משקל הוא דפוס עיצובי מבני שבו אובייקט שמציג עצמו כמופע ייחודי במקומות שונים בתוכנית, למעשה, אינו כך. קל משקל חוסך בזיכרון על ידי שיתוף המצב המשותף של אובייקטים בינם לבין עצמם, במקום אחסון אותם נתונים בכל אובייקט. כדי להבין את המהות, בואו נסתכל על הדוגמה הפשוטה ביותר. נניח שיש לנו ממשק עובדים:
public interface Employee {
   void work();
}
ויש כמה יישומים, למשל, עורך דין:
public class Lawyer implements Employee {

   public Lawyer() {
       System.out.println("Юрист взят в штат.");
   }

   @Override
   public void work() {
       System.out.println("Решение юридических вопросов...");
   }
}
ורואה החשבון:
public class Accountant implements Employee{

   public Accountant() {
       System.out.println("Бухгалтер взят в штат.");
   }

   @Override
   public void work() {
       System.out.println("Ведение бухгалтерского отчёта....");
   }
}
השיטות מאוד מותנות: אנחנו רק צריכים לראות שהן מבוצעות. אותו מצב חל על הקונסטרוקטור. הודות לפלט המסוף, נראה מתי נוצרים אובייקטים חדשים. יש לנו גם מחלקת עובדים, שתפקידה להנפיק את העובד המבוקש, ואם הוא לא נמצא, להעסיק אותו ולהנפיק בהתאם לבקשה:
public class StaffDepartment {
   private Map<String, Employee> currentEmployees = new HashMap<>();

   public Employee receiveEmployee(String type) throws Exception {
       Employee result;
       if (currentEmployees.containsKey(type)) {
           result = currentEmployees.get(type);
       } else {
           switch (type) {
               case "Бухгалтер":
                   result = new Accountant();
                   currentEmployees.put(type, result);
                   break;
               case "Юрист":
                   result = new Lawyer();
                   currentEmployees.put(type, result);
                   break;
               default:
                   throw new Exception("Данный сотрудник в штате не предусмотрен!");
           }
       }
       return result;
   }
}
כלומר, ההיגיון פשוט: אם יש יחידה נתונה, החזר אותה, אם לא, צור אותה, הנח אותה באחסון (משהו כמו מטמון) והחזיר אותה. עכשיו בואו נראה איך הכל עובד:
public static void main(String[] args) throws Exception {
   StaffDepartment staffDepartment = new StaffDepartment();
   Employee empl1  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl2  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl3  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl4  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl5  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl6  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl7  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl8  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl9  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl10  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
}
ובקונסולה, בהתאם, יהיה פלט:
עורך הדין נשכר. פתרון בעיות משפטיות... נשכר רואה חשבון. ניהול דו"ח חשבונאי.... פתרון סוגיות משפטיות... ניהול דו"ח חשבונאי.... פתרון בעיות משפטיות... ניהול דו"ח חשבונאי.... פתרון סוגיות משפטיות... ניהול דו"ח חשבונאי.... פתרון בעיות משפטיות... שמירה על דוחות חשבונאיים...
כפי שניתן לראות, נוצרו רק שני אובייקטים, שנעשה בהם שימוש חוזר פעמים רבות. הדוגמה פשוטה מאוד, אבל היא מדגימה בבירור כיצד שימוש בתבנית זו יכול לחסוך במשאבים שלנו. ובכן, כפי ששמתם לב, ההיגיון של הדפוס הזה דומה מאוד להיגיון של מאגר הביטוח. אתה יכול לקרוא עוד על סוגי דפוסי GOF במאמר זה .ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 7 - 3

64. איך לפצל מיתר לחלקים? אנא ספק דוגמה לקוד המתאים

ברור, שאלה זו היא על שיטת הפיצול . למחלקה String יש שתי גרסאות של שיטה זו:
String split(String regex);
ו
String split(String regex);
regex הוא מפריד שורות - ביטוי רגולרי כלשהו המחלק מחרוזת למערך של מחרוזות, לדוגמה:
String str = "Hello, world it's Amigo!";
String[] arr = str.split("\\s");
for (String s : arr) {
  System.out.println(s);
}
הדברים הבאים ייצאו לקונסולה:
שלום, עולם זה אמיגו!
כלומר, ערך המחרוזת שלנו חולק למערך של מחרוזות והמפריד היה רווח (להפרדה, נוכל להשתמש בביטוי רגיל ללא רווח "\\s" ורק בביטוי מחרוזת " " ). לשיטה השנייה, העמוסה יתר על המידה, יש ארגומנט נוסף - limit . limit - הערך המרבי המותר של המערך המתקבל. כלומר, כאשר המחרוזת כבר פוצלה למספר המרבי המותר של תת-מחרוזות, לא יהיה פיצול נוסף, ולאלמנט האחרון תהיה "שארית" של המחרוזת שאולי תת-מפוצלת. דוגמא:
String str = "Hello, world it's Amigo!";
String[] arr = str.split(" ", 2);
for (String s : arr) {
  System.out.println(s);
}
פלט מסוף:
שלום, עולם זה אמיגו!
כפי שאנו יכולים לראות, אלמלא המגבלה = 2 , ניתן היה לפצל את האלמנט האחרון של המערך לשלוש תת מחרוזות.ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 7 - 4

65. מדוע מערך תווים עדיף על מחרוזת לאחסון סיסמה?

ישנן מספר סיבות להעדיף מערך על פני מחרוזת בעת אחסון סיסמה: 1. אי-שינוי של מאגר מחרוזות ושל מחרוזת. כשמשתמשים במערך ( char[] ), נוכל למחוק את הנתונים במפורש לאחר שנסיים איתו. כמו כן, נוכל לשכתב את המערך כמה שנרצה, והסיסמה התקפה לא תהיה בשום מקום במערכת, אפילו לפני איסוף האשפה (מספיק לשנות כמה תאים לערכים לא חוקיים). יחד עם זאת, String הוא מחלקה בלתי ניתנת לשינוי. כלומר, אם נרצה לשנות את ערכו, נקבל חדש ואילו הישן יישאר במאגר המיתרים. אם ברצוננו להסיר את ערך ה-String של סיסמה, זו יכולה להיות משימה קשה מאוד, מכיוון שאנו צריכים את אוסף האשפה כדי להסיר את הערך מ- String pool , ויש סבירות גבוהה שערך String זה יישאר שם למשך הרבה זמן. כלומר, במצב זה, String נחות ממערך ה-char מבחינת אבטחת אחסון הנתונים. 2. אם ערך המחרוזת יוצא בטעות לקונסולה (או יומנים), הערך עצמו יוצג:
String password = "password";
System.out.println("Пароль - " + password);
פלט מסוף:
סיסמה
במקביל, אם בטעות פלטת מערך לקונסולה:
char[] arr = new char[]{'p','a','s','s','w','o','r','d'};
System.out.println("Пароль - " + arr);
יהיה gobbledygook לא מובן בקונסולה:
סיסמה - [C@7f31245a
למעשה לא gobbledygook, אבל: [C הוא שם המחלקה הוא מערך char , @ הוא מפריד, ואחריו 7f31245a הוא קוד hash הקסדצימלי. 3. המסמך הרשמי, Java Cryptography Architecture Guide, מזכיר במפורש אחסון סיסמאות ב- char[] במקום String : "זה נראה הגיוני לאסוף ולאחסן סיסמה באובייקט מסוג java.lang.String . עם זאת, יש כאן אזהרה: אובייקטי מחרוזת אינם ניתנים לשינוי, כלומר, אין שיטות מוגדרות המאפשרות לשנות (לדרוס) את התוכן של אובייקט מחרוזת או לבטל לאחר השימוש. תכונה זו הופכת את אובייקטי המחרוזת לבלתי מתאימים לאחסון מידע רגיש כגון סיסמאות משתמש. במקום זאת, עליך תמיד לאסוף ולאחסן מידע אבטחה רגיש במערך תווים".ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 7 - 5

Enum

66. תן תיאור קצר של Enum ב-Java

Enum הוא ספירה, קבוצה של קבועי מחרוזת המאוחדים על ידי סוג משותף. הוכרז באמצעות מילת המפתח - enum . הנה דוגמה עם enum - תפקידים תקפים בבית ספר מסוים:
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD
}
המילים הכתובות באותיות גדולות הן אותם קבועי ספירה המוצהרים בצורה פשוטה, ללא שימוש באופרטור החדש . השימוש בספירות מפשט מאוד את החיים, מכיוון שהן עוזרות להימנע מטעויות ובלבול במתן שמות (שכן יכולה להיות רק רשימה מסוימת של ערכים). באופן אישי, אני מוצא אותם מאוד נוחים בשימוש בעיצוב ההגיוני של Switch .

67. האם Enum יכולה ליישם ממשקים?

כן. אחרי הכל, ספירות חייבות לייצג יותר מסתם אוספים פסיביים (כגון תפקידים). ב-Java, הם יכולים לייצג אובייקטים מורכבים יותר עם פונקציונליות מסוימת, כך שייתכן שתצטרך להוסיף להם פונקציונליות נוספת. זה גם יאפשר לך להשתמש ביכולות של פולימורפיזם על ידי החלפת ערך ה-enum במקומות שבהם נדרש סוג הממשק המיושם.

68. האם Enum יכול להאריך שיעור?

לא, זה לא יכול, מכיוון ש-enum הוא תת-מחלקה ברירת מחדל של המחלקה הגנרית Enum <T> , כאשר T מייצג את סוג ה-enum הגנרי. זה אינו אלא מחלקת בסיס משותפת לכל סוגי ה-enum של שפת Java. ההמרה של enum למחלקה נעשית על ידי מהדר Java בזמן ההידור. הרחבה זו אינה מצוינת במפורש בקוד, אך היא תמיד נוכחת באופן בלתי נראה.

69. האם ניתן ליצור Enum ללא מופעי אובייקט?

לגביי, השאלה קצת מוזרה, או שלא הבנתי אותה עד הסוף. יש לי שני פירושים: 1. האם יכול להיות מנה ללא ערכים - כן כמובן שזה יהיה משהו כמו מחלקה ריקה - חסר משמעות:
public enum Role {
}
ומתקשר:
var s = Role.values();
System.out.println(s);
נקבל בקונסולה:
[Lflyweight.Role;@9f70c54
(מערך ריק של ערכי תפקידים ) 2. האם ניתן ליצור enum ללא האופרטור החדש - כן, כמובן. כפי שאמרתי למעלה, אינך צריך להשתמש באופרטור החדש עבור ערכי enum (ספירות) , מכיוון שאלו ערכים סטטיים.

70. האם נוכל לעקוף את שיטת toString() עבור Enum?

כן, כמובן שאתה יכול לעקוף את שיטת toString() כדי להגדיר דרך ספציפית להצגת ה-enum שלך בעת קריאה למתודה toString (כאשר מתרגמים את ה-enum למחרוזת רגילה, למשל, עבור פלט לקונסולה או ללוגים).
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD;

   @Override
   public String toString() {
       return "Выбрана роль - " + super.toString();
   }
}
זה הכל להיום, עד החלק הבא!ניתוח שאלות ותשובות מראיונות למפתח Java.  חלק 7 - 6
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION