JavaRush /مدونة جافا /Random-AR /تحليل الأسئلة والأجوبة من المقابلات لمطور جافا. الجزء 11

تحليل الأسئلة والأجوبة من المقابلات لمطور جافا. الجزء 11

نشرت في المجموعة
مرحبًا! حتى أسرع سفينة بدون مسار سوف تنجرف ببساطة على طول الأمواج. إذا كنت تقرأ مقالتي الآن، فمن المؤكد أن لديك هدفا. الشيء الرئيسي هو عدم الضلال، ولكن متابعة خطك حتى النهاية - لتصبح مطور جافا. أريد اليوم أن أواصل تحليلي لأكثر من 250 سؤالًا لمطوري Java، مما سيساعدك على تغطية بعض الثغرات في النظرية. تحليل الأسئلة والأجوبة من المقابلات لمطور جافا.  الجزء 11 - 1

97. هل يتم فرض شروط إعادة تعريف الاتفاق عند إعادة تعريف متساوين؟

يجب أن تتوافق طريقة يساوي () المتجاوزة مع الشروط (القواعد) التالية:
  • الانعكاسية - لأي قيمة يجب أن يُرجع تعبير مثل x.equals(x) دائمًا القيمة true (عندما يكون x != null ).

  • التناظر - لأي قيم x و يجب أن يُرجع التعبير بالصيغة x.equals(y) صحيحًا فقط إذا أعاد y.equals(x) صحيحًا .

  • العبور - بالنسبة لأي قيم x و y و z ، إذا كانت x.equals(y) تُرجع صحيحًا و y.equals(z) تُرجع أيضًا صحيحًا ، فيجب أن تُرجع x.equals(z) صحيحًا .

  • الاتساق - بالنسبة لأي قيم x و فإن الاستدعاء المتكرر لـ x.equals(y) سيعيد دائمًا قيمة الاستدعاء السابق لهذه الطريقة، بشرط ألا تتغير الحقول المستخدمة لمقارنة الكائنين بين الاستدعاءات .

  • المقارنة خالية - لأي قيمة سيؤدي استدعاء x.equals(null) إلى إرجاع false .

98. ماذا يحدث إذا لم تقم بتجاوز Equals وHashCode؟

في هذه الحالة، سيقوم hashCode() بإرجاع رقم تم إنشاؤه بناءً على موقع الذاكرة الذي تم تخزين الكائن المحدد فيه. أي أن كائنين لهما نفس الحقول تمامًا سيحصلان على قيم مختلفة عند استدعاء hashCode () غير متجاوز (بعد كل شيء، يتم تخزينهما في مواقع ذاكرة مختلفة). يقارن يساوي () الذي لم يتم تجاوزه المراجع لمعرفة ما إذا كانت تشير إلى نفس الكائن أم لا. أي أن المقارنة تتم من خلال == ، وفي حالة الكائنات التي لها نفس الحقول، فإنها سترجع دائمًا خطأ . لن يكون صحيحًا إلا عند مقارنة المراجع بنفس الكائن. في بعض الأحيان يكون هناك منطق في عدم تجاوز هذه الأساليب. على سبيل المثال، تريد أن تكون كافة الكائنات من فئة معينة فريدة وتجاوز هذه الأساليب لن يؤدي إلا إلى إفساد منطق التفرد. الشيء الرئيسي هو فهم الفروق الدقيقة بين الأساليب المتجاوزة وغير المتجاوزة واستخدام كلا الطريقتين اعتمادًا على الموقف.

99. لماذا يكون التناظر صحيحًا فقط إذا كانت قيمة x.equals(y) صحيحة؟

قليلا من السؤال الغريب. إذا كان الكائن A يساوي الكائن B، فإن الكائن B يساوي الكائن A. وإذا كان B لا يساوي الكائن A، فكيف يكون العكس ممكنًا؟ هذا منطق بسيط. تحليل الأسئلة والأجوبة من المقابلات لمطور جافا.  الجزء 11 - 2

100. ما هو الاصطدام في HashCode؟ كيفية التعامل معها؟

تصادم hashCode هو موقف يكون فيه كائنين مختلفين لهما نفس قيمة hashCode . كيف يكون هذا ممكنا؟ الحقيقة هي أنه تم تعيين رمز التجزئة إلى النوع الصحيح ، والذي بدوره يتراوح نطاقه من -2147483648 إلى 2147483647، أي ما يقرب من 4 مليارات عدد صحيح مختلف. وهذا النطاق ضخم، ولكنه ليس بلا حدود. لذلك، تكون المواقف ممكنة عندما يكون لكائنين مختلفين تمامًا نفس رمز التجزئة. وهذا أمر مستبعد إلى حد كبير، ولكنه ممكن. يمكن لوظيفة التجزئة التي يتم تنفيذها بشكل سيء أيضًا أن تزيد من تكرار رموز التجزئة المتطابقة، والتي ستعيد، على سبيل المثال، أرقامًا في نطاق صغير، مما سيزيد من فرصة الاصطدامات. لمكافحة الاصطدام، يجب أن يكون لديك تنفيذ جيد لطريقة hashCode بحيث يكون انتشار القيم الحد الأقصى وفرصة تكرار القيم ضئيلة.

101. ماذا يحدث إذا تغير أحد العناصر المشاركة في عقد HashCode من قيمته؟

إذا تم تغيير أحد العناصر المشاركة في حساب رمز التجزئة، فسيتم تغيير رمز التجزئة للكائن نفسه (إذا كانت وظيفة التجزئة جيدة). لذلك، يوصى في HashMap باستخدام كائنات غير قابلة للتغيير (غير قابلة للتغيير) كمفتاح، لأن حالتها الداخلية (الحقول) لا يمكن تغييرها بعد الإنشاء. وفقا لذلك، لا يتم تحويل رمز التجزئة الخاص بهم بعد الإنشاء. إذا كنت تستخدم كائنًا قابلاً للتغيير كمفتاح، فعند تغيير حقول هذا الكائن، سيتغير رمز التجزئة الخاص به، ونتيجة لذلك، يمكنك فقدان هذا الزوج في HashMap . بعد كل شيء، سيتم تخزينه في دلو رمز التجزئة الأصلي، وبعد تغييره، سيتم البحث عنه في دلو آخر. تحليل الأسئلة والأجوبة من المقابلات لمطور جافا.  الجزء 11 - 3

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 .

  • تحويل كائن الوسيطة إلى نوع واحد (في حال كان كائنًا من النوع الأصلي).

  • مقارنة حقل فئة بدائية (بعد كل شيء، المقارنة عبر =! كافية لذلك )، إذا لم يكن الحقل متساويًا - خطأ .

  • التحقق من وجود حقل غير بدائي خاليًا ومساويًا (في السلسلة، يتم تجاوز الطريقة وستتم مقارنتها بشكل صحيح)، إذا كان كلا الحقلين خاليين أو يساويان ، فسينتهي التحقق وترجع الطريقة صحيحًا .

رمز التجزئة:
  • تعيين قيمة رمز التجزئة الأولية على عمر الكائن البدائي .

  • ضرب رمز التجزئة الحالي في 31 (لمزيد من الانتشار) وإضافة رمز التجزئة لحقل سلسلة غير أولية (إذا لم يكن فارغًا).

  • إرجاع النتيجة.

  • نتيجة لتجاوز رمز التجزئة هذا، فإن الكائنات التي تحمل نفس الاسم وقيم int ستعيد دائمًا نفس القيمة.

103. ما الفرق بين استخدام if (obj مثيل الطالب) وإذا (getClass() == obj.getClass())؟

دعونا نلقي نظرة على ما يفعله كل نهج:
  • يتحقق مثيل ما إذا كان مرجع الكائن الموجود على الجانب الأيسر هو مثيل للنوع الموجود على الجانب الأيمن أو نوع فرعي منه.

  • getClass() == ... يتحقق من هوية النوع.

أي أنه إذا كان getClass() يتحقق من الهوية الكاملة للفئة، فسيعود المثيل صحيحًا حتى لو كان الكائن مجرد نوع فرعي، مما يمكن أن يمنحنا المزيد من المرونة عند استخدام تعدد الأشكال بشكل فعال. في الواقع، يعد كلا النهجين جيدًا إذا فهمت ميزات عملهما وقمت بتطبيقهما في الأماكن الصحيحة.

104. أعط وصفًا موجزًا ​​لطريقة الاستنساخ ().

Clone () هي إحدى طرق فئة الكائن ، والغرض منها هو إنشاء وإرجاع نسخة من الكائن الحالي (نسخة من الكائن الحالي). تحليل الأسئلة والأجوبة من المقابلات لمطور جافا.  الجزء 11 - 4لاستخدامها، تحتاج إلى تنفيذ واجهة العلامة القابلة للاستنساخ :
Student implements Cloneable
وتجاوز طريقة clone() نفسها :
@Override
protected Object clone() throws CloneNotSupportedException {
 return super.clone();
}
بعد كل شيء، فهو محمي في فئة الكائن ، أي أنه سيكون مرئيًا فقط في فئة الطالب نفسها ، ولكنه غير مرئي للفصول من الخارج.

105. ما هي خصوصية طريقة clone() التي تعمل مع حقول كائن من النوع المرجعي؟

عند استنساخ الكائنات، يتم نسخ القيم الأولية وقيمة مراجع الكائنات فقط. هذا يعني أنه إذا كان الكائن يحتوي على رابط لكائن آخر في مجاله الداخلي، فسيتم استنساخ هذا الرابط فقط، ولكن لن يتم استنساخ هذا الكائن الآخر نفسه. في الواقع، هذا ما يسمونه بالاستنساخ السطحي. حسنًا، ماذا لو كنت بحاجة إلى استنساخ كامل مع استنساخ جميع الكائنات المتداخلة؟ كيف تتأكد من أن هذه ليست نسخًا من الروابط، ولكنها نسخ كاملة للكائنات مع خلايا الذاكرة الأخرى المشغولة في الكومة؟ في الواقع، كل شيء بسيط للغاية - ولهذا تحتاج أيضًا إلى تجاوز طريقة clone() في كل فئة من هذه الكائنات الداخلية وإضافة واجهة علامة - Cloneable . عندها لن يتم نسخ الإشارات إلى الكائنات، بل الكائنات نفسها، لأنها الآن لديها أيضًا القدرة على نسخ نفسها.

الاستثناءات

106. ما الفرق بين الخطأ والاستثناء؟

كل من الاستثناءات والأخطاء هي فئات فرعية من فئة Throwable . ومع ذلك، لديهم اختلافاتهم. يشير الخطأ إلى مشكلة تحدث بشكل أساسي بسبب عدم كفاية موارد النظام. ويجب ألا يكتشف تطبيقنا هذه الأنواع من المشكلات. بعض أمثلة الأخطاء هي تعطل النظام وخطأ نفاد الذاكرة. تحدث الأخطاء غالبًا في وقت التشغيل لأنها من النوع غير المحدد. تحليل الأسئلة والأجوبة من المقابلات لمطور جافا.  الجزء 11 - 5الاستثناءات هي المشاكل التي يمكن أن تحدث في وقت التشغيل وفي وقت الترجمة. يحدث هذا عادةً في التعليمات البرمجية التي يكتبها المطورون. وهذا يعني أن الاستثناءات أكثر قابلية للتنبؤ بها وأكثر اعتمادًا علينا كمطورين. وفي الوقت نفسه، تكون الأخطاء أكثر عشوائية وأكثر استقلالية عنا، بل تعتمد على مشاكل في النظام نفسه الذي يعمل فيه تطبيقنا.

107. ما هو الفرق بين المحدد وغير المحدد، والاستثناء، والرمي، والرميات.

كما قلت سابقًا، الاستثناء هو خطأ أثناء تنفيذ البرنامج وأثناء التجميع الذي حدث في الكود الذي كتبه المطور (بسبب بعض المواقف غير الطبيعية). "تم التحديد" هو نوع من الاستثناءات التي يجب معالجتها دائمًا باستخدام آلية محاولة الالتقاط أو طرحها في الطرق المذكورة أعلاه. يتم استخدام الرميات في رأس الطريقة للإشارة إلى الاستثناءات المحتملة التي تطرحها الطريقة. أي أن هذه هي آلية "رمي" الاستثناءات في الأساليب المذكورة أعلاه. يعد Unchecked نوعًا من الاستثناءات التي لا تحتاج إلى معالجة وعادة ما تكون أقل قابلية للتنبؤ بها وأقل احتمالية لحدوثها. ومع ذلك، يمكن أيضًا معالجتها إذا رغبت في ذلك. يُستخدم Throw عند طرح استثناء يدويًا، على سبيل المثال:
throw new Exception();

108. ما هو التسلسل الهرمي للاستثناءات؟

التسلسل الهرمي للاستثناءات كبير جدًا وواسع النطاق، بل إنه واسع جدًا بحيث لا يمكن إخبار كل شيء عنه هنا. لذلك، سننظر فقط في روابطها الرئيسية: تحليل الأسئلة والأجوبة من المقابلات لمطور جافا.  الجزء 11 - 6هنا في أعلى التسلسل الهرمي نرى الفئة - Throwable - فئة عامة، سلف التسلسل الهرمي للاستثناء، والذي ينقسم بدوره إلى:
  • خطأ - أخطاء فادحة لا يمكن التحقق منها.
  • استثناء - الاستثناءات المحددة.
ينقسم الاستثناء إلى استثناءات مختلفة لوقت التشغيل لم يتم التحقق منها واستثناءات متعددة محددة.

109. ما هو الاستثناء المحدد وغير المحدد؟

كما قلت من قبل:
  • محددة - الاستثناءات التي يجب عليك التعامل معها بطريقة ما، أي إما معالجتها في كتلة محاولة الالتقاط ، أو "إعادة توجيهها" إلى الطريقة المذكورة أعلاه. للقيام بذلك، في توقيع الطريقة، بعد إدراج وسائط الطريقة، تحتاج إلى استخدام الكلمة الأساسية trows <نوع الاستثناء> ، والتي تشير لمستخدمي الطريقة إلى أن الطريقة يمكنها طرح هذا الاستثناء (شيء مثل التحذير) ونقل مسؤولية التعامل مع الاستثناء لمستخدمي هذه الطريقة.

  • غير محددة - الاستثناءات التي لا تحتاج إلى معالجة، حيث لا يتم التحقق منها في وقت الترجمة، وكقاعدة عامة، لا يمكن التنبؤ بها. أي أن الاختلاف الرئيسي مع المحدد هو أن آليات محاولة الالتقاط أو الرمي تعمل بنفس الطريقة بالنسبة لهم، ولكنها ليست إلزامية.

101. اكتب مثالاً على اعتراض ومعالجة استثناء في كتلة محاولة الالتقاط الخاصة بطريقة ما

try{                                                 // начало блока перехвата
 throw new Exception();                             // ручной бросок исключения
} catch (Exception e) {                              // данное исключение и его потомки будут перехватываться
 System.out.println("Упс, что-то пошло не так =("); // вывод некоторого исключения в консоль
}

102. اكتب مثالاً لالتقاط الاستثناء والتعامل معه باستخدام الاستثناءات الخاصة بك

أولاً، دعونا نكتب فئة الاستثناء الخاصة بنا، والتي ترث من الاستثناء وتتجاوز منشئه برسالة خطأ:
public class CustomException extends Exception {

 public CustomException(final String message) {
   super(message);
 }
}
حسنًا، سنرميها يدويًا ونعترضها كما في السؤال السابق:
try{
 throw new CustomException("Упс, что-то пошло не так =(");
} catch (CustomException e) {
 System.out.println(e.getMessage());
}
ومرة أخرى، عند تشغيله، سوف تحصل على الإخراج التالي إلى وحدة التحكم:
عفوا حدث خطأ ما =(
Разбор вопросов и ответов с собеседований на Java-разработчика. Часть 11 - 7يمكنك معرفة المزيد عن الاستثناءات هنا . حسنا، هذا كل شيء لهذا اليوم! نراكم في الجزء التالي!
مواد أخرى في السلسلة:
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION