JavaRush /مدونة جافا /Random-AR /الطرق الافتراضية في Java 8: ما الذي يمكنهم فعله وما لا يم...
Spitfire
مستوى

الطرق الافتراضية في Java 8: ما الذي يمكنهم فعله وما لا يمكنهم فعله؟

نشرت في المجموعة
ترجمة مقال بقلم بيتر فيرهاس بتاريخ أبريل 2014. الطرق الافتراضية في Java 8: ما الذي يمكنهم فعله وما لا يمكنهم فعله؟  - 1من المترجم: ظهر مصطلح " الطريقة الافتراضية " للتو في Java ولست متأكدًا مما إذا كانت هناك ترجمة ثابتة له إلى اللغة الروسية. سأستخدم مصطلح "الطريقة الافتراضية"، على الرغم من أنني لا أعتقد أنها مثالية. أدعوك لمناقشة ترجمة أكثر نجاحًا.

ما هي الطريقة الافتراضية

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

تعدد الميراث؟

تصبح الأمور أكثر تعقيدًا إذا قام الفصل بتنفيذ أكثر من واجهة واحدة (على سبيل المثال، اثنتين)، ويقومون بتنفيذ نفس الطريقة الافتراضية. ما هي الطريقة التي سوف يرثها الفصل؟ الجواب لا. في هذه الحالة، يجب على الفصل تنفيذ الطريقة نفسها (إما بشكل مباشر أو عن طريق وراثتها من فئة أخرى). يكون الوضع مشابهًا إذا كانت واجهة واحدة فقط تحتوي على طريقة افتراضية، وفي الأخرى تكون نفس الطريقة مجردة. يحاول Java 8 الانضباط وتجنب المواقف الغامضة. إذا تم الإعلان عن الأساليب في أكثر من واجهة واحدة، فلن يرث الفصل أي تطبيق افتراضي - سوف تحصل على خطأ في الترجمة. على الرغم من أنك قد لا تحصل على خطأ في الترجمة إذا كان فصلك قد تم تجميعه بالفعل. Java 8 ليس قويًا بدرجة كافية في هذا الصدد. هناك أسباب لذلك لا أريد الخوض في مناقشتها (على سبيل المثال: تم إصدار إصدار Java بالفعل وقد مر وقت المناقشات منذ فترة طويلة، وبشكل عام، هذا ليس المكان المناسب لهم).
  • لنفترض أن لديك واجهتين ويقوم الفصل بتنفيذ كليهما.
  • تطبق إحدى الواجهات الطريقة الافتراضية m().
  • يمكنك تجميع كافة الواجهات والفئة.
  • يمكنك تغيير واجهة لا تحتوي على طريقة m() عن طريق الإعلان عنها كطريقة مجردة.
  • يمكنك تجميع الواجهة المعدلة فقط.
  • ابدأ الفصل.
الطرق الافتراضية في Java 8: ما الذي يمكنهم فعله وما لا يمكنهم فعله؟  - 2في هذه الحالة يعمل الفصل. لا يمكنك تجميعه مع الواجهات المحدثة، ولكن تم تجميعه مع الإصدارات الأقدم وبالتالي يعمل. الآن
  • قم بتغيير الواجهة باستخدام طريقة m() المجردة وأضف تطبيقًا افتراضيًا.
  • تجميع الواجهة المعدلة.
  • تشغيل الفئة: خطأ.
عندما تكون هناك واجهتان توفران تطبيقًا افتراضيًا لطريقة ما، فلا يمكن استدعاء هذه الطريقة في فئة ما لم يتم تنفيذها بواسطة الفئة نفسها (مرة أخرى، إما بمفردها أو موروثة من فئة أخرى). الطرق الافتراضية في Java 8: ما الذي يمكنهم فعله وما لا يمكنهم فعله؟  - 3متوافق مع الفئة. يمكن تحميله بواجهة معدلة. قد يتم تشغيله حتى يتم استدعاء طريقة لها تطبيق افتراضي في كلا الواجهتين.

رمز المثال

الطرق الافتراضية في Java 8: ما الذي يمكنهم فعله وما لا يمكنهم فعله؟  - 4لتوضيح ما سبق، قمت بإنشاء دليل اختبار لفئة C.java و3 أدلة فرعية للواجهات في الملفين I1.java وI2.java. يحتوي الدليل الجذر للاختبار على الكود المصدري لفئة C.java. يحتوي الدليل الأساسي على نسخة من الواجهات المناسبة للتنفيذ والتجميع: الواجهة I1 لها طريقة افتراضية m(); لا تحتوي واجهة I2 على أي طرق حتى الآن. يحتوي الفصل على طريقة mainحتى نتمكن من تنفيذها لاختبارها. فهو يتحقق مما إذا كان هناك أي وسيطات لسطر الأوامر، حتى نتمكن من تنفيذها بسهولة إما مع أو بدون استدعاء m().
~/github/test$ cat C.java
public class C implements I1, I2 {
  public static void main(String[] args) {
    C c = new C();
    if( args.length == 0 ){
      c.m();
    }
  }
}
~/github/test$ cat base/I1.java
public interface I1 {
  default void m(){
    System.out.println("hello interface 1");
  }
}
~/github/test$ cat base/I2.java
public interface I2 {
}
يمكنك ترجمة وتشغيل الفصل من سطر الأوامر.
~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1
يحتوي الدليل المتوافق على نسخة من واجهة I2 التي تعلن أن أسلوب m() مجرد، وأيضًا، لأسباب فنية، نسخة غير معدلة من I1.java.
~/github/test$ cat compatible/I2.java

public interface I2 {
  void m();
}
لا يمكن استخدام هذه المجموعة لتجميع فئة C:
~/github/test$ javac -cp .:compatible C.java
C.java:1: error: C is not abstract and does not override abstract method m() in I2
public class C implements I1, I2 {
       ^
1 error
رسالة الخطأ دقيقة للغاية. ومع ذلك، لدينا C.class من تجميع سابق، وإذا قمنا بتجميع الواجهات في الدليل المتوافق، سيكون لدينا واجهتين لا يزال من الممكن استخدامهما لتشغيل الفصل:
~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1
يحتوي الدليل الثالث - wrong- على الإصدار I2، والذي يعلن أيضًا عن الطريقة m():
~/github/test$ cat wrong/I2.java
public interface I2 {
  default void m(){
    System.out.println("hello interface 2");
  }
}
لا داعي للقلق بشأن التجميع. على الرغم من الإعلان عن الطريقة مرتين، إلا أنه لا يزال من الممكن استخدام الفئة وتشغيلها حتى يتم استدعاء الطريقة m(). هذا هو ما نحتاج إلى وسيطة سطر الأوامر من أجله:
~/github/test$ javac wrong/*.java
~/github/test$ java -cp .:wrong C
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting default methods: I1.m I2.m
    at C.m(C.java)
    at C.main(C.java:5)
~/github/test$ java -cp .:wrong C x
~/github/test$

خاتمة

عندما تقوم بنقل مكتبتك إلى Java 8 وتغيير واجهاتك لتشمل الأساليب الافتراضية، فمن المحتمل ألا تواجه أية مشكلات. على الأقل، هذا ما يأمله مطورو مكتبة Java 8 عندما يضيفون وظائف. لا تزال التطبيقات التي تستخدم مكتبتك تستخدمها لـ Java 7، حيث لا توجد طرق افتراضية. إذا تم استخدام عدة مكتبات معًا، فهناك احتمال حدوث تعارض. كيفية تجنب ذلك؟ صمم واجهة برمجة التطبيقات (API) الخاصة بمكتبتك بنفس الطريقة السابقة. لا تكتفى بالاعتماد على قدرات الأساليب الافتراضية. إنهم الملاذ الأخير. اختر الأسماء بعناية لتجنب الاصطدامات مع الواجهات الأخرى. دعونا نرى كيف سيتم تطوير تطوير Java باستخدام هذه الميزة.
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION