71. ماذا يحدث إذا لم نتجاوز طريقة toString() الخاصة بـ Enum؟
لنفترض أن لدينا التعداد التالي :public enum Role {
STUDENT,
TEACHER,
DIRECTOR,
SECURITY_GUARD;
}
لنعرض حقل الطالب على وحدة التحكم عن طريق استدعاء الأسلوب toString() الخاص به:
System.out.println(Role.STUDENT.toString());
ونتيجة لذلك، نحصل على إخراج وحدة التحكم التالية:
72. هل يمكنك الإعلان عن مُنشئ داخل التعداد؟
نعم بالطبع. المُنشئ هو الذي يحدد قيم الحقول الداخلية للتعداد . على سبيل المثال، دعونا نضيف حقلين إلى التعداد السابق ( ageFrom و ageTo ) للإشارة إلى الفئة العمرية لكل دور:public enum Role {
STUDENT(5,18),
TEACHER(20,60),
DIRECTOR(40,70),
SECURITY_GUARD(18,50);
int ageFrom;
int ageTo;
Role(int ageFrom, int ageTo) {
this.ageFrom = ageFrom;
this.ageTo = ageTo;
}
}
73. ما الفرق بين == و يساوي ()؟
يعد هذا أحد أسئلة المقابلة الأكثر شيوعًا التي يتم طرحها على مطوري Java المحتملين. في البداية، عند مقارنة القيم البسيطة ( int ، char ، double ...) نستخدم == ، نظرًا لأن هذه المتغيرات تحتوي على قيم ملموسة يمكن مقارنتها مباشرة. علاوة على ذلك، فإن المتغيرات البدائية ليست كائنات كاملة، فهي لا ترث فئة الكائن ولا تحتوي على طريقة يساوي () . إذا كنا نتحدث عن مقارنة المتغيرات التي تشير إلى كائنات، فيجب أن نعرف أن == يقارن فقط قيمة المراجع، أي ما إذا كانت تشير إلى نفس الكائن أم لا. حتى لو كانت جميع البيانات الموجودة في كائن واحد متطابقة مع جميع البيانات الموجودة في كائن آخر، فإن استخدام == للمقارنة سيؤدي إلى نتيجة سلبية ( خطأ )، لأنهما كائنان منفصلان. كما كنت قد خمنت، فإننا نستخدم طريقة يساوي () لمقارنة المتغيرات المرجعية. يعد هذا أحد الأساليب القياسية لفئة الكائن ، وهو ضروري لإجراء مقارنة كاملة للكائنات. ولكن يجب أن أقول على الفور أنه لكي تعمل هذه الطريقة بشكل صحيح، يجب تجاوزها للإشارة إلى كيفية مقارنة الكائنات بالضبط. إذا لم تقم بتجاوز الطريقة، فستحصل على التنفيذ الافتراضي، الذي يقارن الكائنات باستخدام == . في IntelliJ IDEA، يمكنك تجاوزه تلقائيًا باستخدام اختصار IDEA: Alt+Insert . في النافذة التي تظهر، حدد يساوي () و hashCode () . ثم حدد الحقول التي ينبغي أن تشارك. هاهو! يتم تنفيذ الأساليب تلقائيا. فيما يلي مثال لكيفية قيام طريقة يساوي التي يتم إنشاؤها تلقائيًا بالبحث عن أبسط فئة Cat ممكنة مع حقلين - 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 Cat cat = (Cat) o;
return this.age == cat.age &&
Objects.equals(this.name, cat.name);
}
عندما يتعلق الأمر بالتعداد ، لا يوجد فرق عملي بين == و يساوي() . بعد كل شيء، يقوم التعداد بتخزين الثوابت، وحتى عندما نقارن القيم المتطابقة باستخدام == ، فسوف نحصل على القيمة true ، نظرًا لأن المراجع المقارنة ستشير دائمًا إلى نفس الكائنات. واستخدام يساوي () يعطينا النتيجة الصحيحة أيضًا. إذا ذهبت إلى نص طريقة يساوي لـ Enum ، سترى أن فئة Enum لديها التنفيذ التالي: في الداخل يمكننا أن نرى مقارنة قديمة جيدة للمراجع! للتلخيص، بالنسبة إلى enum s، يمكننا المقارنة بشكل صحيح باستخدام كل من == و equals() .
74. ماذا تفعل طريقة Enum الترتيبية ()؟
عندما نستدعي الطريقة int ordinal() في حقل التعداد ، نحصل على فهرس الحقل ذو الأساس الصفري في قائمة قيم التعداد. لنستدعي هذه الطريقة في حقل في تعداد الدور ، والذي تناولناه سابقًا:System.out.println(Role.DIRECTOR.ordinal());
وفقًا لذلك، تعرض وحدة التحكم:
75. هل يمكن استخدام Enum مع TreeSet أو TreeMap في Java؟
يمكننا استخدام أنواع التعداد في TreeSet و TreeMap . ويمكننا أن نكتب هذا:TreeSet<Role> treeSet = new TreeSet<>();
treeSet.add(Role.SECURITY_GUARD);
treeSet.add(Role.DIRECTOR);
treeSet.add(Role.TEACHER);
treeSet.add(Role.STUDENT);
treeSet.forEach(System.out::println);
وستعرض وحدة التحكم:
76. ما هي العلاقة بين طريقتي Enum الترتيبية () وcompareTo ()؟
كما ذكرنا سابقًا، تقوم الدالة ordinal() بإرجاع فهرس الحقل في قائمة حقول التعداد. أيضًا، عند نظرنا في السؤال السابق، رأيت أنه عندما يتم وضع حقول التعداد في TreeSet ( وهي مجموعة مفروزة)، فإنها تأخذ الترتيب الذي تم الإعلان عنه في التعداد . وكما نعلم، يقوم TreeSet و TreeMap بفرز العناصر عن طريق استدعاء طريقة CompareTo() للواجهة القابلة للمقارنة . يخبرنا هذا أن فئة Enum تنفذ الواجهة القابلة للمقارنة ، مما يعني أنها تنفذ طريقة CompareTo() ، والتي تستخدم الطريقة الترتيبية () داخليًا لتحديد ترتيب الفرز. بالذهاب إلى فئة Enum ، يمكننا تأكيد افتراضنا: وهذا هو نص الطريقة نفسها: لم يتم استدعاء الطريقة الترتيبية () هنا. بدلا من ذلك، يتم استخدام المتغير الترتيبي ، وهو رقم الفهرس للعنصر في التعداد. الطريقة الترتيبية () نفسها ليست أكثر من مجرد مُحصل للمتغير الترتيبي .77. اكتب مثالاً على التعداد
في الأسئلة التي تمت مناقشتها أعلاه، قدمت بالفعل أمثلة على التعداد . لا أرى أي سبب لتكرار الكود هنا. على سبيل المثال، راجع السؤال 72 بخصوص المُنشئ في التعداد.78. هل يمكن استخدام التعداد في حالة التبديل؟
يمكن أن يكون وينبغي أن يكون! بالنظر إلى تجربتي، سألاحظ أن أحد الاستخدامات الأكثر شيوعًا للتعداد هو في البناءات المنطقية مثل عبارات التبديل . في هذه الحالة، يمكنك توفير جميع الحالات الممكنة - بمجرد كتابة المنطق لكل حقل تعداد ، فلن تحتاج حتى إلى عبارة افتراضية ! بعد كل شيء، إذا كنت تستخدم String أو قيمة رقمية، مثل int ، فقد تتلقى قيمة غير متوقعة، لكن هذا مستحيل مع enum . إليك ما ستبدو عليه عبارة التبديل في المثال أعلاه:public void doSomething(Role role) {
switch (role) {
case STUDENT:
// some logic for STUDENT
break;
case TEACHER:
// some logic for TEACHER
break;
case DIRECTOR:
// some logic for DIRECTOR
break;
case SECURITY_GUARD:
// some logic for SECURITY_GUARD
break;
}
}
79. كيف يمكنني الحصول على كافة القيم الممكنة للتعداد؟
إذا كنت بحاجة إلى الحصول على جميع قيم التعداد الممكنة، فهناك طريقة value() ، والتي تُرجع مصفوفة من جميع القيم الممكنة للتعداد بترتيبها الطبيعي (أي بالترتيب الذي تم تحديدها به في التعداد ) . مثال:Role[] roles = Role.values();
for (Role role : roles) {
System.out.println(role);
}
سيكون لدينا ما يلي على وحدة التحكم:
دفق API
80. ما هو الدفق في جافا؟
تعد Java Stream API طريقة جديدة نسبيًا للتفاعل مع تدفق البيانات، مما يسمح لنا بمعالجة البيانات الضخمة بشكل أكثر سهولة وإحكامًا، بالإضافة إلى معالجة البيانات بالتوازي بين عدد من التدفقات، مما قد يؤدي إلى تعزيز الأداء.81. تسمية الخصائص الرئيسية للمعاملات
الموضوع هنا هو Stream API، لكن السؤال يتعلق بالمعاملات. حسنًا... أولاً، دعونا نفهم ما هي المعاملة. المعاملة هي مجموعة من العمليات المتسلسلة في قاعدة البيانات . إنه يمثل وحدة منطقية للعمل. يمكن تنفيذ المعاملة بشكل مستقل عن المعاملات المتزامنة الأخرى إما بشكل كامل وبنجاح، وبالتالي الحفاظ على سلامة البيانات، أو عدم تنفيذها على الإطلاق، وفي هذه الحالة ليس لها أي تأثير. تحتوي المعاملات على أربع خصائص رئيسية، والتي يمكننا تذكرها بسهولة بفضل الاختصار ACID . دعونا نرى ما يعنيه كل حرف من هذا الاختصار: A يرمز إلى Atomicity . تضمن هذه الخاصية عدم الالتزام بأي معاملة جزئيًا في النظام. إما سيتم تنفيذ جميع عملياتها الفرعية، أو لن يتم تنفيذ أي منها ( الكل أو لا شيء ). С تعني الاتساق . تضمن هذه الخاصية أن كل معاملة ناجحة ستؤدي إلى نتائج صالحة فقط. بمعنى آخر، هذا ضمان أنه في حالة نجاح المعاملة، فسيتم الالتزام بجميع قواعد النظام الخاصة ببيانات محددة. إذا لم تنجح المعاملة، فلن يتم تنفيذها وستعود بيانات النظام إلى حالتها السابقة. أنا أؤيد العزلة . تعني هذه الخاصية أنه عند تنفيذ معاملة ما، يجب ألا تؤثر المعاملات المتزامنة على نتائجها. هذه الخاصية كثيفة الاستخدام للموارد، لذلك، كقاعدة عامة، يتم تنفيذها جزئيًا، مما يسمح بمستويات معينة من العزلة التي تحل مشاكل عزل محددة. سنناقش هذا بمزيد من التفصيل في السؤال التالي. D يرمز إلى المتانة . تضمن هذه الخاصية أنه إذا تلقى المستخدم تأكيدًا بإتمام المعاملة، فيمكنه التأكد من عدم إلغاء التغييرات بسبب بعض الفشل. أي أنه يمكنك التأكد من أن بعض حالات فشل نظام التشغيل لن تؤثر على بياناتك إذا كنت قد تلقيت بالفعل تأكيدًا بأن معاملتك انتهت بنجاح.82. ما هي مستويات عزل المعاملة؟
كما قلت سابقًا، عندما يتعلق الأمر بخصائص ACID، فإن ضمان العزل هو عملية كثيفة الاستخدام للموارد. وفقا لذلك، يتم تنفيذ هذه الخاصية جزئيا. هناك مستويات مختلفة من العزلة: كلما ارتفع المستوى، زاد التأثير على الأداء. قبل أن ننتقل إلى مستويات عزل المعاملات، نحتاج إلى النظر في المشاكل المختلفة التي تحدث بسبب عدم كفاية عزل المعاملات :-
القراءة الوهمية : عندما يؤدي نفس الطلب، الذي يتم استدعاؤه أكثر من مرة في معاملة واحدة، إلى نتائج مختلفة بسبب عمليات الإدراج بواسطة معاملة أخرى؛
-
القراءات غير القابلة للتكرار : عندما يُنتج نفس الطلب، الذي يتم استدعاؤه أكثر من مرة ضمن معاملة واحدة، بيانات مختلفة بسبب التغييرات (التحديثات) والحذف بواسطة معاملة أخرى؛
-
القراءات القذرة : قراءة البيانات التي لم يتم الالتزام بها بعد، والتي تمت إضافتها أو تعديلها بواسطة معاملة ما، ثم تم التراجع عنها لاحقًا؛
-
التحديثات المفقودة : عندما يتم تغيير كتلة بيانات واحدة في وقت واحد من خلال معاملات مختلفة، ويتم فقدان جميع التغييرات باستثناء التغيير الأخير (على غرار حالة السباق في مؤشرات الترابط المتعددة).
مستوى العزلة | يقرأ الوهمية | قراءات غير قابلة للتكرار | يقرأ القذرة | التحديث المفقود |
---|---|---|---|---|
قابل للتسلسل | + | + | + | + |
قراءة متكررة | - | + | + | + |
قراءة ملتزمة | - | - | + | + |
قراءة غير ملتزم بها | - | - | - | + |
لا أحد | - | - | - | - |
83. ما الفرق بين البيان والبيان المُعد؟
قمنا هنا بتغيير الانتقال فجأة إلى ميزات JDBC . على أية حال، دعونا أولاً نكتشف ما هو المقصود بالبيان . إنه كائن يستخدم لتكوين استعلامات SQL. يستخدم JDBC ثلاثة أنواع: البيان ، و PreparedStatement ، و CallableStatement . لن نأخذ في الاعتبار CallableStatement اليوم. بدلاً من ذلك، نحن نتحدث عن الفرق بين البيان و PreparedStatement .-
يتم استخدام البيان لتنفيذ استعلامات SQL بسيطة بدون معلمات إدخال وقت التشغيل. يمكن أن يقبل PreparStatement معلمات الإدخال في وقت التشغيل.
-
لتعيين معلمات لـ PreparationStatement ، تتم كتابة معلمات الإدخال كعلامات استفهام في الطلب، بحيث يمكن استبدالها ببعض القيم باستخدام محددات مختلفة، مثل setDouble() و setFloat() و setInt() و setTime() ... هذا يعني أنك لن تقوم بإدراج نوع خاطئ من البيانات في الطلب.
-
تم تجميع PreparedStatement مسبقًا ويستخدم التخزين المؤقت، لذلك يمكن تنفيذه بشكل أسرع قليلاً من الطلب المقدم من كائنات البيان . ونتيجة لذلك، يتم إنشاء عبارات SQL التي يتم تنفيذها بشكل متكرر ككائنات PreparationStatement لتحسين الأداء.
-
البيان عرضة لإدخال SQL، لكن PreparedStatement يمنعهم.
GO TO FULL VERSION