CodeGym /مدونة جافا /Random-AR /أفضل 50 سؤالاً وإجابات في مقابلات العمل لـ Java Core. الج...
John Squirrels
مستوى
San Francisco

أفضل 50 سؤالاً وإجابات في مقابلات العمل لـ Java Core. الجزء 1

نشرت في المجموعة
مرحبًا بالجميع، سيداتي وسادتي، مهندسي البرمجيات! دعونا نتحدث عن أسئلة المقابلة. حول ما تحتاج إلى الاستعداد له وما تحتاج إلى معرفته. يعد هذا وقتًا رائعًا لمراجعة هذه النقاط أو دراستها لأول مرة. أفضل 50 سؤالاً وإجابات في مقابلات العمل لـ Java Core.  الجزء 1 - 1 انتهى بي الأمر بمجموعة واسعة من الأسئلة المتداولة حول OOP وبناء جملة Java واستثناءات Java والمجموعات وتعدد مؤشرات الترابط، والتي سأقسمها إلى عدة أجزاء لتسهيل الأمر. من الصعب تغطية كل شيء مرة واحدة، ولكنني آمل أن توفر هذه المادة أساسًا جيدًا لأولئك الذين يستعدون للعثور على وظيفتهم الأولى كمبرمج. للحصول على أفضل فهم واحتفاظ، أنصحك بالتمشيط من خلال مصادر أخرى أيضًا. يمكنك الحصول على فهم أعمق للمفهوم من خلال تناوله من عدة زوايا مختلفة. مهم:سنتحدث فقط عن Java قبل الإصدار 8. ولن يتم النظر هنا في جميع الابتكارات التي جاءت في الإصدارات 9 و10 و11 و12 و13. نرحب بأي أفكار/تعليقات حول كيفية تحسين الإجابات . استمتع بقراءتك. دعنا نذهب!

مقابلة جافا: أسئلة حول OOP

1. ما هي خصائص جافا؟

إجابة:
  1. مفاهيم OOP:

    1. اتجاه الكائن
    2. ميراث
    3. التغليف
    4. تعدد الأشكال
    5. التجريد
  2. عبر الأنظمة الأساسية: يمكن تشغيل برنامج Java على أي نظام أساسي دون أي تغييرات. بالطبع، يتطلب هذا تثبيت JVM (جهاز Java الظاهري).

  3. الأداء العالي: يجعل برنامج التحويل البرمجي Just-In-Time (JIT) الأداء العالي ممكنًا. يقوم برنامج التحويل البرمجي JIT بتحويل الرمز الثانوي إلى رمز الجهاز ثم يبدأ JVM في التنفيذ.

  4. تعدد مؤشرات الترابط: يقوم JVM بإنشاء سلسلة تنفيذ تسمى main thread. يمكن للمبرمج إنشاء سلاسل رسائل متعددة عن طريق الاشتقاق من فئة Thread أو تنفيذ Runnableالواجهة.

2. ما هو الميراث؟

الوراثة تعني أنه يمكن لفئة واحدة أن ترث فئة أخرى (باستخدام الكلمة الأساسية الممتدة ). هذا يعني أنه يمكنك إعادة استخدام التعليمات البرمجية من الفصل الذي ورثته. تُعرف الفئة الحالية باسم superclassوالفئة التي تم إنشاؤها حديثًا هي subclass. يقول الناس أيضًا استخدام المصطلحين الأصل و child.
public class Animal {
   private int age;
}

public class Dog extends Animal {

}
أين Animalهو parentو Dogهو child.

3. ما هو التغليف؟

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

4. ما هو تعدد الأشكال؟

تعدد الأشكال هو قدرة البرنامج على التعامل مع الكائنات ذات الواجهة نفسها بنفس الطريقة، دون معلومات حول نوع الكائن المحدد. وكما يقول المثل، "واجهة واحدة - العديد من التطبيقات". باستخدام تعدد الأشكال، يمكنك دمج واستخدام أنواع مختلفة من الكائنات بناءً على السلوكيات المشتركة. على سبيل المثال، لدينا فئة من الحيوانات تضم ذريتين: الكلب والقط. تتمتع فئة الحيوان العامة بسلوك مشترك بين الجميع، وهو القدرة على إصدار صوت. نستخدم إمكانات متعددة الأشكال عندما نحتاج إلى جمع كل ما يرث فئة الحيوان وتنفيذ طريقة "إصدار الصوت". وهنا كيف يبدو:
List<Animal> animals = Arrays.asList(new Cat(), new Dog(), new Cat());
animals.forEach(animal -> animal.makeSound());
وبعبارة أخرى، تعدد الأشكال مفيد. وهذا ينطبق أيضًا على الأساليب متعددة الأشكال (المحملة بشكل زائد). كيفية استخدام تعدد الأشكال

أسئلة المقابلة حول بناء جملة جافا

5. ما هو المنشئ في جافا؟

يتمتع المنشئون بالخصائص التالية:
  1. عند إنشاء كائن جديد، يستخدم البرنامج المنشئ المناسب لإنشائه.
  2. المنشئ يشبه الطريقة. تكمن سماته المميزة في عدم وجود قيمة إرجاع (بما في ذلك الفراغ) وأن اسمه هو نفس اسم الفئة.
  3. إذا لم يتم إنشاء مُنشئ بشكل صريح، فسيتم إنشاء مُنشئ فارغ تلقائيًا.
  4. يمكن تجاوز المنشئ.
  5. إذا قمت بتعريف مُنشئ بمعلمات ولكنك تحتاج أيضًا إلى مُنشئ بدون معلمات، فيجب عليك إنشائه بشكل منفصل، لأنه لن يتم إنشاؤه تلقائيًا.

6. أي الفئتين لا ترث الكائن؟

لا تنخدع بالأسئلة الخادعة، فلا توجد مثل هذه الفصول. ترث جميع الفئات فئة الكائن إما مباشرة أو من خلال أسلافها!

7. ما هو المتغير المحلي؟

هذا سؤال شائع آخر للمقابلة لمطوري Java. المتغير المحلي هو متغير يتم تعريفه داخل الطريقة ويكون موجودًا طالما يتم تنفيذ الطريقة. بمجرد انتهاء التنفيذ، يتوقف المتغير المحلي عن الوجود. فيما يلي برنامج يستخدم متغيرًا محليًا يسمى helloMessage في الطريقة الرئيسية ():
public static void main(String[] args) {
   String helloMessage;
   helloMessage = "Hello, World!";
   System.out.println(helloMessage);
}

8. ما هو متغير المثيل؟

متغير المثيل هو متغير تم الإعلان عنه داخل الفصل. إنه موجود طالما أن الكائن موجود. على سبيل المثال، لدينا فئة Bee، والتي تحتوي على متغيرين — nectarLoad وmaxNectarLoad:
public class Bee {

   /**
    * Current nectar load
    */
   private double nectarLoad;

   /**
    * Maximum nectar that can the bee can collect.
    */
   private double maxNectarLoad = 20.0;

  ...
}

9. ما هي معدّلات الوصول؟

معدّلات الوصول هي آلية لتخصيص الوصول إلى الفئات والأساليب والمتغيرات. توجد المعدلات التالية، وهي مدرجة حسب ترتيب زيادة الوصول:
  1. private- يتم استخدام معدّل الوصول هذا في الأساليب والحقول والمنشئات. يقتصر الوصول على الفئة التي تم الإعلان عنها.
  2. package-private (default)- هذا هو مستوى الوصول الافتراضي للفئات. يقتصر الوصول على الحزمة المحددة التي يتم فيها الإعلان عن فئة أو طريقة أو متغير أو مُنشئ.
  3. protected- يوفر معدل الوصول هذا نفس مستوى الوصول كما هو الحال package-privateمع إضافة الوصول للفئات التي ترث فئة مع المعدل protected.
  4. public- يُستخدم مستوى الوصول هذا أيضًا للفصول الدراسية. ويعني مستوى الوصول هذا أن هناك وصولاً كاملاً إلى التطبيق بأكمله.
أفضل 50 سؤالاً وإجابات في مقابلات العمل لـ Java Core.  الجزء 1 - 2

10. ما هو أسلوب التجاوز؟

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

11. ما هي توقيعات الطريقة؟

أفضل 50 سؤالاً وإجابات في مقابلات العمل لـ Java Core.  الجزء 1 - 3توقيع الطريقة هو مزيج من اسم الطريقة والوسائط التي تأخذها الطريقة. توقيع الطريقة هو المعرف الفريد للطريقة عند التحميل الزائد للطرق.

12. ما هو أسلوب التحميل الزائد؟

التحميل الزائد للطريقة هو إحدى سمات تعدد الأشكال حيث نقوم بتغيير توقيع الطريقة لإنشاء طرق متعددة تؤدي نفس الإجراء:
  • نفس الاسم
  • حجج مختلفة
  • يمكن أن تكون هناك أنواع مختلفة من الإرجاع
على سبيل المثال، يمكن تحميل تابع ArrayListالصنف add()بشكل زائد، مما يسمح لنا بإضافة طرق مختلفة اعتمادًا على وسيطات الإدخال:
  • add(Object o)- تضيف هذه الطريقة ببساطة كائنًا
  • add(int index, Object o)- تضيف هذه الطريقة كائنًا إلى فهرس محدد
  • add(Collection<Object> c)- تضيف هذه الطريقة قائمة بالكائنات
  • add(int index, Collection<Object> c)- تضيف هذه الطريقة قائمة بالكائنات بدءًا من فهرس محدد.

13. ما هي الواجهة؟

لا تدعم Java الميراث المتعدد. للتغلب على هذا القيد، تمت إضافة واجهات بالشكل الذي نعرفه ونحبه؛) لفترة طويلة، كانت الواجهات تحتوي على طرق فقط دون أي تنفيذ. في سياق هذه الإجابة، دعونا نتحدث عنهم. على سبيل المثال:

public interface Animal {
   void makeSound();
   void eat();
   void sleep();
}
بعض التفاصيل تتبع من هذا:
  • جميع الأساليب في الواجهة عامة ومجردة
  • جميع المتغيرات نهائية عامة ثابتة
  • لا ترث الفئات الواجهات (أي أننا لا نستخدم الكلمة الأساسية الممتدة). بدلاً من ذلك، تقوم الفئات بتنفيذها (على سبيل المثال، نستخدم الكلمة الأساسية للأدوات). علاوة على ذلك، يمكنك تنفيذ أي عدد تريده من الواجهات.
  • يجب أن توفر الفئات التي تنفذ الواجهة تطبيقًا لجميع الأساليب الموجودة في الواجهة.
مثله:
public class Cat implements Animal {
   public void makeSound() {
       // Method implementation
   }

   public void eat() {
       // Implementation
   }

   public void sleep() {
       // Implementation
   }
}

14. ما هي الطريقة الافتراضية في الواجهة؟

الآن دعونا نتحدث عن الأساليب الافتراضية. لماذا هم؟ لمن هم؟ تمت إضافة هذه الطرق لخدمة "كلتا اليدين". ما الذي أتحدث عنه؟ حسنًا، من ناحية، كانت هناك حاجة لإضافة وظائف جديدة: lambdas وStream API. من ناحية أخرى، كان من الضروري الاحتفاظ بما تشتهر به Java - التوافق مع الإصدارات السابقة. وللقيام بذلك، احتاجت الواجهات إلى بعض الحلول الجديدة الجاهزة. هذه هي الطريقة التي جاءت إلينا الأساليب الافتراضية. الطريقة الافتراضية هي طريقة يتم تنفيذها في الواجهة، ويتم تمييزها بالكلمة defaultالأساسية. على سبيل المثال، الطريقة المعروفة stream()في Collectionالواجهة. صدقني، هذه الواجهة ليست بسيطة كما تبدو. أو أيضًا forEach()الطريقة المشهورة بنفس القدر في Iterableالواجهة. كما أنها لم تكن موجودة حتى تمت إضافة الطرق الافتراضية. بالمناسبة، يمكنك أيضًا القراءة عنها على CodeGym هنا .

15. كيف إذن نرث طريقتين افتراضيتين متطابقتين؟

الإجابة السابقة حول ماهية الطريقة الافتراضية تطرح سؤالاً آخر. إذا كان بإمكانك تنفيذ الأساليب في الواجهات، فمن الناحية النظرية يمكنك تنفيذ واجهتين بنفس الطريقة. كيف نفعل ذلك؟ فيما يلي واجهتان مختلفتان بنفس الطريقة:
interface A {
   default void foo() {
       System.out.println("Foo A");
   }
}

interface B {
   default void foo() {
       System.out.println("Foo B");
   }
}
ولدينا فئة تنفذ هاتين الواجهتين. ولكن كيف نختار طريقة معينة في الواجهة A أو B؟ البناء الخاص التالي يسمح بذلك: A.super.foo():
public class C implements A, B {
   public void fooA() {
       A.super.foo();
   }

   public void fooB() {
       B.super.foo();
   }
}
وبالتالي، fooA()ستستخدم الطريقة foo()الطريقة الافتراضية للواجهة A، بينما fooB()ستستخدم الطريقة foo()طريقة الواجهة B.

16. ما هي الأساليب والطبقات المجردة؟

في جافا، abstractهي كلمة محجوزة. يتم استخدامه للدلالة على الطبقات والأساليب المجردة. أولا، نحتاج إلى تعريفات. الطريقة المجردة هي طريقة يتم الإعلان عنها باستخدام abstractالكلمة الأساسية دون تطبيق في فئة مجردة. أي أن هذه طريقة كما في الواجهة، ولكن مع إضافة كلمة أساسية، على سبيل المثال:
public abstract void foo();
الفئة المجردة هي فئة تم تمييزها أيضًا بالكلمة abstractالأساسية:
public abstract class A {

}
تحتوي الفئة المجردة على العديد من الميزات:
  • لا يمكنك إنشاء كائن من فئة مجردة
  • يمكن أن يكون لها أساليب مجردة
  • وقد لا تحتوي أيضًا على طرق مجردة
هناك حاجة إلى فئات مجردة للتجريد (آسف للحشو) الذي يحتوي على مجموعة من السلوكيات والحالات الشائعة (أي الأساليب والمتغيرات). الحياة الحقيقية مليئة بالأمثلة. كل شيء حولنا. "حيوان"، "سيارة"، "شكل هندسي"، وما إلى ذلك.

17. ما الفرق بين String وStringBuilder وStringBuffer؟

Stringيتم تخزين القيم في تجمع سلسلة ثابتة. بمجرد إنشاء سلسلة، تظهر في هذا التجمع. ولا يمكنك حذفه. على سبيل المثال:
String name = "book";
سيشير المتغير إلى تجمع السلاسل الثابتة. أفضل 50 سؤالاً وإجابات في مقابلات العمل لـ Java Core.  الجزء 1 - 4عند ضبط متغير الاسم على قيمة مختلفة، لدينا:
name = "pen";
يبدو تجمع السلسلة الثابتة كما يلي: أفضل 50 سؤالاً وإجابات في مقابلات العمل لـ Java Core.  الجزء 1 - 5وبعبارة أخرى، تظل كلا القيمتين هناك. المخزن المؤقت للسلسلة:
  • Stringيتم تخزين القيم في مكدس. إذا تم تغيير قيمة، فإن القيمة الجديدة ستحل محل القيمة القديمة.
  • String Bufferمتزامن وبالتالي فهو آمن للخيط.
  • نظرًا لسلامة الخيط، فإن أدائه ضعيف.
مثال:
StringBuffer name = “book”;
أفضل 50 سؤالاً وإجابات في مقابلات العمل لـ Java Core.  الجزء 1 - 6بمجرد تغيير قيمة متغير الاسم، تتغير القيمة الموجودة في المكدس: أفضل 50 سؤالاً وإجابات في مقابلات العمل لـ Java Core.  الجزء 1 - 7StringBuilder هو نفسه تمامًا StringBuffer، ولكنه ليس آمنًا لمؤشر الترابط. ونتيجة لذلك، فهو أسرع بشكل ملحوظ من StringBuffer.

18. ما الفرق بين الفئة المجردة والواجهة؟

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

19. لماذا يتم الوصول إلى عنصر في المصفوفة O(1)؟

تم طرح هذا السؤال حرفيًا في مقابلتي الأخيرة. وكما تعلمت لاحقا، فإن الغرض من هذا السؤال هو معرفة كيف يفكر الشخص. ومن الواضح أن هناك قيمة عملية قليلة في هذه المعرفة. مجرد معرفة ذلك يكفي. أولاً، نحتاج إلى توضيح أن O(1) هو رمز للتعقيد الزمني لخوارزمية "الوقت الثابت". بمعنى آخر، يشير هذا التصنيف إلى أسرع وقت للتنفيذ. للإجابة على هذا السؤال، علينا أن نأخذ بعين الاعتبار ما نعرفه عن المصفوفات. لإنشاء intمصفوفة يجب علينا كتابة ما يلي:
int[] intArray = new int[100];
ويمكن استخلاص عدة استنتاجات من هذا النحو:
  1. عندما يتم الإعلان عن مصفوفة، فإن نوعها معروف. إذا كان النوع معروفًا، فإن حجم كل خلية في المصفوفة يكون معروفًا.
  2. حجم المصفوفة بأكملها معروف.
ويترتب على ذلك أنه لفهم الخلية التي سنكتب إليها، نحتاج فقط إلى حساب مساحة الذاكرة التي سنكتب إليها. بالنسبة للكمبيوتر، هذا أمر سهل للغاية. يعرف الكمبيوتر أين تبدأ الذاكرة المخصصة وعدد العناصر وحجم كل خلية. كل هذا يعني أن مكان الكتابة سيكون مساويًا لمكان بداية المصفوفة + حجم كل خلية مضروبًا في الفهرس.

فكيف نصل إلى O(1) عند الوصول إلى الكائنات في ArrayList؟

هذا السؤال يتبع مباشرة السؤال السابق. الحقيقة هي أنه عند العمل مع مصفوفة تحتوي على عناصر أولية، فإننا نعرف مسبقًا (في وقت الإنشاء) حجم نوع العنصر. ولكن ماذا نفعل إذا كان لدينا هذا النوع من التسلسل الهرمي للميراث وأردنا أفضل 50 سؤالاً وإجابات في مقابلات العمل لـ Java Core.  الجزء 1 - 8إنشاء مجموعة لعناصر من النوع A وإضافة تطبيقات مختلفة (B وC وD):
List<A> list = new ArrayList();
list.add(new B());
list.add(new C());
list.add(new D());
list.add(new B());
وفي هذه الحالة كيف نحسب حجم كل خلية؟ بعد كل شيء، سيكون كل كائن مختلفًا، وربما مع حقول إضافية مختلفة. ما يجب القيام به؟ هنا يتم طرح السؤال بطريقة تهدف إلى إرباكك. نحن نعلم أن المجموعة لا تخزن الكائنات مباشرة. يقوم فقط بتخزين الإشارات إلى الكائنات. وجميع المراجع لها نفس الحجم، وهذا معروف. ونتيجة لذلك، فإننا نحسب العناوين هنا بنفس الطريقة كما في السؤال السابق.

21. التشغيل التلقائي والفتح

الخلفية التاريخية: يعد autoboxing وunboxing بعضًا من الابتكارات الرئيسية في JDK 5. Autoboxing هي عملية التحويل التلقائي من نوع بدائي إلى فئة مجمعة مقابلة. Unboxing هو عكس autoboxing تمامًا. إنها عملية تحويل فئة المجمع إلى فئة بدائية. ولكن إذا كانت قيمة الغلاف هي null, NullPointerExceptionفسيتم طرح a أثناء فتح العلبة.

البدائيون والأغلفة المقابلة لهم

بدائية الطبقة المجمعة
منطقية منطقية
كثافة العمليات عدد صحيح
بايت بايت
شار شخصية
يطفو يطفو
طويل طويل
قصير قصير
مزدوج مزدوج

// يحدث التشغيل التلقائي:

  • عند تعيين بدائية لمرجع إلى فئة المجمع:

    قبل جافا 5:

    // Manual boxing (the way it was BEFORE Java 5).
    public void boxingBeforeJava5() {
       Boolean booleanBox = new Boolean(true);
       Integer intBox = new Integer(3);
       // And so on for other types
    }
    
    After Java 5:
    // Automatic boxing (the way it became in Java 5).
    public void boxingJava5() {
       Boolean booleanBox = true;
       Integer intBox = 3;
       // And so on for other types
    }
  • عندما يتم تمرير عنصر بدائي كوسيطة إلى طريقة تتوقع غلافًا:

    public void exampleOfAutoboxing() {
       long age = 3;
       setAge(age);
    }
    
    public void setAge(Long age) {
       this.age = age;
    }

// يحدث فتح العلبة:

  • عندما نقوم بتعيين مثيل لفئة مجمعة لمتغير بدائي:

    // BEFORE Java 5:
    int intValue = new Integer(4).intValue();
    double doubleValue = new Double(2.3).doubleValue();
    char c = new Character((char) 3).charValue();
    boolean b = Boolean.TRUE.booleanValue();
    
    // And after JDK 5:
    int intValue = new Integer(4);
    double doubleValue = new Double(2.3);
    char c = new Character((char) 3);
    boolean b = Boolean.TRUE;
  • أثناء العمليات الحسابية. تنطبق العمليات فقط على الأنواع البدائية، لذا يعد فك العلبة إلى الأنواع الأولية أمرًا ضروريًا.

    // BEFORE Java 5:
    Integer integerBox1 = new Integer(1);
    Integer integerBox2 = new Integer(2);
    
    // A comparison used to require this:
    integerBox1.intValue() > integerBox2.intValue()
    
    // In Java 5
    integerBox1 > integerBox2
  • عند تمرير مثيل لفئة مجمعة إلى طريقة تأخذ البدائية المقابلة:

    public void exampleOfAutoboxing() {
       Long age = new Long(3);
       setAge(age);
    }
    
    public void setAge(long age) {
       this.age = age;
    }

22. ما هي الكلمة الرئيسية النهائية وأين يتم استخدامها؟

يمكن استخدام الكلمة finalالأساسية في المتغيرات والأساليب والفئات.
  1. لا يمكن تغيير قيمة المتغير النهائي بعد تهيئته.
  2. فصل أخير عقيم :) لا يمكن أن يكون له أطفال.
  3. لا يمكن تجاوز الطريقة النهائية بواسطة السليل.
لقد قمنا بتغطية الأشياء رفيعة المستوى. الآن دعونا نغوص بشكل أعمق.

المتغيرات النهائية

توفر لنا Java طريقتين للإعلان عن متغير وتعيين قيمة له:
  1. يمكنك الإعلان عن متغير وتهيئته لاحقًا.
  2. يمكنك الإعلان عن متغير وتعيين قيمة على الفور.
فيما يلي مثال يوضح هذه الاستخدامات للمتغيرات النهائية:
public class FinalExample {

   // A static final variable that is immediately initialized:
   final static String FINAL_EXAMPLE_NAME = "I'm likely the final one";

   // A final variable that is not initialized, but will only work if you
   // initialize it in the constructor:
   final long creationTime;

   public FinalExample() {
       this.creationTime = System.currentTimeMillis();
   }

   public static void main(String[] args) {
       FinalExample finalExample = new FinalExample();
       System.out.println(finalExample.creationTime);

       // The final FinalExample.FINAL_EXAMPLE_NAME field cannot be accessed
//    FinalExample.FINAL_EXAMPLE_NAME = "Not you're not!";

       // The final Config.creationTime field cannot be accessed
//    finalExample.creationTime = 1L;
   }
}

هل يمكن اعتبار المتغير النهائي ثابتا؟

وبما أننا لا نستطيع تعيين قيم جديدة للمتغيرات النهائية، فيبدو أن هذه متغيرات ثابتة. لكن للوهلة الأولى فقط: إذا كان نوع بيانات المتغير هو immutable، فنعم، فهو ثابت. ولكن إذا كان نوع البيانات mutableقابلاً للتغيير، فسيكون من الممكن استخدام الأساليب والمتغيرات لتغيير قيمة الكائن المشار إليه بواسطة متغير final. وبسبب هذا، لا يمكن أن يسمى ثابتا. يوضح المثال التالي أن بعض المتغيرات النهائية هي في الواقع ثوابت، في حين أن بعضها الآخر ليس كذلك، حيث يمكن تغييرها.
public class FinalExample {

   // Immutable final variables
   final static String FINAL_EXAMPLE_NAME = "I'm likely the final one";
   final static Integer FINAL_EXAMPLE_COUNT  = 10;

   // Mutable final variables
   final List<String> addresses = new ArrayList();
   final StringBuilder finalStringBuilder = new StringBuilder("Constant?");
}

المتغيرات النهائية المحلية

عندما finalيتم إنشاء متغير ضمن طريقة، فإنه يسمى متغير local final:
public class FinalExample {

   public static void main(String[] args) {
       // You can do this
       final int minAgeForDriveCar = 18;

       // Or you can do this, in a for-each loop:
       for (final String arg : args) {
           System.out.println(arg);
       }
   }

}
يمكننا استخدام الكلمة الأساسية النهائية في حلقة for المحسنة، لأنه يتم إنشاء متغير جديد بعد كل تكرار للحلقة. ضع في اعتبارك أن هذا لا ينطبق على حلقة for العادية، لذلك سنحصل على خطأ أثناء الترجمة.
// The final local j variable cannot be assigned
for (final int i = 0; i < args.length; i ++) {
   System.out.println(args[i]);
}

الطبقة النهائية

تم الإعلان عن فئة finalلا يمكن تمديدها. وبعبارة أكثر بساطة، لا يمكن لأي فئة أخرى أن ترثها. مثال ممتاز للفئة finalفي JDK هو String. الخطوة الأولى لإنشاء فئة غير قابلة للتغيير هي وضع علامة عليها final، وبالتالي منع توسيعها:
public final class FinalExample {
}

// Compilation error!
class WantsToInheritFinalClass extends FinalExample {
}

الطرق النهائية

عندما يتم وضع علامة نهائية على طريقة ما، فإنها تسمى طريقة نهائية (هذا منطقي، أليس كذلك؟). لا يمكن تجاوز الطريقة النهائية في فئة فرعية. بالمناسبة، تعتبر طرق الانتظار () وإخطار () الخاصة بفئة الكائن نهائية، لذلك ليس لدينا القدرة على تجاوزها.
public class FinalExample {
   public final String generateAddress() {
       return "Some address";
   }
}

class ChildOfFinalExample extends FinalExample {

   // Compilation error!
   @Override
   public String generateAddress() {
       return "My OWN Address";
   }
}

كيف وأين يتم استخدام Final في Java

  • استخدم الكلمة الأساسية الأخيرة لتحديد بعض الثوابت على مستوى الفصل الدراسي؛
  • قم بإنشاء المتغيرات النهائية للكائنات التي لا تريد تغييرها. على سبيل المثال، الخصائص الخاصة بالكائن التي يمكننا استخدامها لأغراض التسجيل.
  • إذا كنت لا ترغب في تمديد الفصل الدراسي، فقم بوضع علامة عليه كنهائي.
  • إذا كنت بحاجة إلى إنشاء فئة غير قابلة للتغيير، فأنت بحاجة إلى جعلها نهائية.
  • إذا كنت تريد ألا يتغير تنفيذ الطريقة في أحفادها، فقم بوضع علامة على الطريقة كـ final. هذا مهم جدًا للتأكد من أن التنفيذ لا يتغير.

23. ما هي الأنواع المتغيرة وغير القابلة للتغيير؟

متقلب

الكائنات القابلة للتغيير هي كائنات يمكن تغيير حالتها ومتغيراتها بعد إنشائها. تتضمن أمثلة الفئات القابلة للتغيير StringBuilder وStringBuffer. مثال:
public class MutableExample {

   private String address;

   public MutableExample(String address) {
       this.address = address;
   }

   public String getAddress() {
       return address;
   }

   // This setter can change the name field
   public void setAddress(String address) {
       this.address = address;
   }

   public static void main(String[] args) {

       MutableExample obj = new MutableExample("First address");
       System.out.println(obj.getAddress());

       // We are updating the name field, so this is a mutable object
       obj.setAddress("Updated address");
       System.out.println(obj.getAddress());
   }
}

غير قابل للتغيير

الكائنات غير القابلة للتغيير هي كائنات لا يمكن تغيير حالتها ومتغيراتها بعد إنشاء الكائن. مفتاح رائع لـ HashMap، ألا تعتقد ذلك؟ :) على سبيل المثال، سلسلة، عدد صحيح، مزدوج، وما إلى ذلك. مثال:
// We'll make this class final so no one can change it
public final class ImmutableExample {

   private String address;

   ImmutableExample(String address) {
       this.address = address;
   }

   public String getAddress() {
       return address;
   }

   // We remove the setter

   public static void main(String[] args) {

       ImmutableExample obj = new ImmutableExample("Old address");
       System.out.println(obj.getAddress());

       // There is no way to change this field, so it is an immutable object
       // obj.setName("new address");
       // System.out.println(obj.getName());

   }
}
في الجزء التالي، سنتناول الأسئلة والأجوبة المتعلقة بالمجموعات. ملفي الشخصي على GitHub أفضل 50 سؤالًا وإجابات لمقابلة العمل لـ Java Core. الجزء 2
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION