بدأت Java 8 في الظهور ، حيث جلب ميزة جديدة: استخدم تعبير Lambda (JSR-335) للبرمجة الوظيفية. سنناقش اليوم جزءًا من Lambda: Extension ، المعروف أيضًا باسم طريقة Defender. تتيح لك هذه الميزة تنفيذ طريقة توفير الأساليب في تعريف الواجهة. على سبيل المثال ، يمكنك تحديد طريقة للواجهات الموجودة (مثل القائمة والخريطة) بحيث لا يحتاج المطورون الآخرون إلى إعادة بناء هذه الطرق ، والتي تشبه إلى حد ما مجردة ، لكنها في الواقع واجهة. بالطبع ، Java 8 متوافق نظريًا مع المكتبات الموجودة.
تجلب طريقة التمديد الافتراضي خصائص ميراث متعددة إلى Java. ربما يمكنك رؤية ظل الميراث المتعدد من خلال هذه الميزة. ولكن لا يزال بإمكانك محاكاة ميراث حالة الحالة. سأصف ميراث الدولة من خلال Mixin في المقالة التالية بالتفصيل.
ما هو مختلط في Mixin؟
الخلط هو فئة مجردة من مجموعة. على سبيل المثال ، إذا كان لديك فئة للإشارة إلى "حصان" ، فيمكنك إنشاء هذه الفئة لإنشاء مثال على "Horse" ، ثم توسيعه عن طريق وراثة مثل "Garage" و "Garden".
Val Myhouse = منزل جديد مع مرآب مع حديقة
من ميراث Mixin ليس مواصفات محددة ، هذه مجرد طريقة تستخدم لإضافة وظائف مختلفة إلى الفئات الموجودة. في OOP ، مع Mixin ، لديك قابلية قراءة الفصل من خلاله.
على سبيل المثال ، هناك طريقة Mixin في وحدة Socketserver من Python.
فئة forkingpserver (forkingmixin ، udpserver): passclass forkingtcpserver (forkingmixin ، tcpserver): pass class class threadingudpserver (threadmixin): passclass threadingtcpserver (twersingmixin ، tcpserver): pass
ما هي طريقة التمديد الظاهري؟
ستقدم Java 8 مفهوم التمديد الظاهري ، والذي يسمى أيضًا طريقة Defender.
يهدف VEM إلى توفير الطريقة الافتراضية لواجهة Java. لا تحتاج هذه المكتبة الثالثة -مثل Hibernate إلى تكرار جميع طرق واجهات برمجة التطبيقات هذه لأنها قدمت بعض الأساليب الافتراضية.
فيما يلي مثال على كيفية تحديد الطريقة في الواجهة:
تمتد مجموعة الواجهة العامة <T> ITERBLE <T> {<R> Collection <R> Filter (ProseDicate <T> P)
محاكاة Java 8 المختلطة
الآن نأتي لتحقيق تأثير مختلط من خلال VEM ، ولكن التحذير مقدمًا هو: من فضلك لا تستخدم في العمل!
التنفيذ التالي ليس آمنًا ، وقد يكون هناك مشكلة في تسرب الذاكرة ، وهو ما يعتمد على الأساليب التي حددتها في الفصل.
بادئ ذي بدء ، نحدد تعريف طريقة (حبة محاكاة) ونوفر الطريقة:
الواجهة العامة switchablemixin {boolean isActivated () افتراضي {return switchlables.isactivated (this) ؛} void setActivated (نشاط منطقي) خطأ {switchables.setActivated (هذا ، المنشط) ؛}}
ثم نحدد فئة الأدوات التي تحتوي على مثيل MAP لحفظ ارتباط الحالات والحالة.
تبديل الفئة النهائية {الخريطة النهائية الثابتة الخاصة Activity ؛} setActivated static static} .Activated = Activated ؛} فئة ثابتة خاصة SwitchableDevicestate {private boolean activated ؛}}
فيما يلي حالة استخدام تبرز ميراث الدولة:
جهاز فئة ثابتة خاصة {} فئة ثابتة خاصة devicea يمتد جهاز SwitchableMixin {}
"أشياء مختلفة تماما"
يبدو أن التنفيذ أعلاه أمر طبيعي ، لكن المهندس المعماري اللغوي الخاص بـ Oracle Brian Goetz سألني سؤالًا مفاده أن التنفيذ الحالي غير قادر على العمل (على افتراض أن سلامة الخيط وتسرب الذاكرة قد تم حلها)
الواجهة goopbrokenmixin {static map <GoplebrokenMixin ، string> packingMap = مجموعات. PUT (هذا ، الاسم) () ؛
ما هي النتيجة التي ستخمنها سيتم عرض هذا الرمز بعد التنفيذ؟
حل الشك
للوهلة الأولى ، لا توجد مشكلة في رمز التنفيذ هذا. X عبارة عن واجهة تحتوي على طريقة واحدة فقط ، لأن GetName و SetName لها بالفعل التعريف الافتراضي ، ولكن لم يتم تعريف طريقة تشغيل الواجهة القابلة للتشغيل. تنفيذ طريقة التشغيل. لذلك ، فإن النتيجة التي تريد هذا البرنامج بعد التنفيذ هي:
x1x2
إذا قمت بحذف طريقة Call of the GetName ، فإن نتيجة التنفيذ تصبح:
mytest $ 1@30ae8764mytest $ 1@123ACF34
يوضح هذان الخطان أن تنفيذ طريقة Makex يأتي من حالتين مختلفتين ، وفي هذا الوقت ، يتم إنشاء OpenJDK 8 الحالي (هنا أستخدم OpenJDK 8 24.0-B07).
على أي حال ، لا يعكس OpenJdk 8 سلوك Java 8 النهائي.
x2x2
إذا لم تتصل بطريقة getName ، فسيتم عرضها:
mytest $ $ lambda $ 1@5506d4eamytest $ $ lambda $ 1@5506d4ea
يبدو أن كل طريقة Makex هي مثيل فردي من نفس الفئة الداخلية المجهولة.
لأنه أثناء التجميع ، لم يخضع تعبير Lambda إلى ترجمة كاملة. تحتوي هذه التعليمات على جميع المعلومات الوصفية الضرورية حول تعبير LABDA في وقت التشغيل. بما في ذلك اسم الطريقة ، ونوع الإدخال ونوع الإخراج ، وطريقة تسمى bootstrap. يتم استخدام طريقة bootstrap لتحديد مثيل استلام هذه الطريقة بمجرد تنفيذ JVM تعليمات الاستدعاء ، وسيقوم JVM بضبط طريقة Lambda metafactory على bootstrap معين.
بالعودة إلى السؤال الآن ، تحول تعبير Lambda إلى طريقة ثابتة خاصة ، () -> {system.out.println ("X") ؛} تم نقلها إلى MyTest:
private static void lambda $ 0 () {system.out.println ("x") ؛}
إذا كنت تستخدم المعلمة الخاصة مع جهاز Javap Counter-Compilation ويمكنك رؤية هذه الطريقة ، فيمكنك أيضًا استخدام المعلمة -C لعرض تحويل أكثر اكتمالًا.
عندما تقوم بتشغيل البرنامج ، يقوم JVM باستدعاء طريقة Lambda Metafactory لمحاولة شرح التعليمات المستدعية. في مثالنا ، عندما يتم استدعاء Makex لأول مرة ، يتم تنشيط Lambda Metafactory مثيلًا لـ X وربط طريقة التشغيل بشكل ديناميكي بطريقة Lambda $ 0 في الذاكرة ، وبالتالي فإن مثيل مكالمتك الثانية هو نفسه المرة الأولى.
هل قمت بإصلاحه؟ هل يوجد حل؟
لا يوجد إصلاح مباشر أو حل لهذه المشكلة. على الرغم من أن برنامج Oracle Java 8 Defaults-Xdlambdatomethod ، لأن هذه المعلمة ليست جزءًا من مواصفات JVM ، فإن تنفيذ الموردين المختلفين و JVM مختلف. للحصول على تعبير Lambda ، فإن الشيء الوحيد الذي يمكنك توقعه هو تنفيذ طريقة الواجهة الخاصة بك في الفصل.
طرق أخرى
حتى الآن ، على الرغم من أن تقليدنا لـ Mixin لا يمكن أن يكون متوافقًا مع Java 8 ، إلا أنه لا يزال من الممكن إضافة خدمات متعددة من خلال الميراث والتعيين المتعددة للوجود. هذه الطريقة هي نمط الحقل الظاهري (وضع الحقل الظاهري).
لذا ألق نظرة على مفتاحنا.
واجهة التبديل {boolean isaction () ؛
نحتاج إلى واجهة قابلة للتبديل ونوفر طريقة تجريد إضافية للعودة إلى التنفيذ القابل للتبديل. تحتوي الطريقة المتكاملة على التعريف الافتراضي.
الواجهة العامة switchable تمتد {switchable getSwitchable ()
بعد ذلك ، نقوم بإنشاء تطبيق كامل قابل للتبديل:
تبديل الفئة العامة تنفذ {private boolean active ؛
هذا مثال على وضع الحقل الافتراضي لدينا:
جهاز الفئة العامة {} يمتد Devicea على الأدوات القابلة للتبديل {Private SwitchableImpl () ؛ getSwitchable القابل للتبديل () {return switchable ؛}}
ختاماً
في هذه المقالة ، نستخدم طريقتين لإضافة خدمات متعددة من خلال طريقة التوسع الظاهري لـ Java 8. تستخدم الطريقة الأولى خريطة لتخزين حالة المثيل. هناك طريقة أخرى تتمثل في استخدام وضع الحقل الظاهري لإرجاع مثال التنفيذ النهائي من خلال getter مجردة. الطريقة الثانية أكثر استقلالية وأمان.
طريقة التمديد الافتراضي هي الميزة الجديدة لـ Java.