وايلدكارد (جافا)

في لغة برمجة جافا ، يُعدّ الحرف البديل? نوعًا خاصًا من وسائط النوع [ 1 ] يتحكم في سلامة النوع عند استخدام الأنواع العامة (المُعَلمة). [ 2 ] يمكن استخدامه في تعريف المتغيرات وإنشاء مثيلاتها، وكذلك في تعريفات الدوال، ولكن ليس في تعريف النوع العام. [ 3 ] [ 4 ] يُعدّ هذا شكلًا من أشكال تعليقات التباين في موقع الاستخدام ، على عكس تعليقات التباين في موقع التعريف الموجودة في لغتي C# و Scala .

التغاير للأنواع العامة

على عكس المصفوفات (التي تتسم بالتغاير في جافا [ 2 ] )، فإنّ التجسيدات المختلفة لنوع عام لا تتوافق مع بعضها البعض، ولا حتى بشكل صريح. [ 2 ] على سبيل المثال، التصريحات

عام < النوع الفائق > عام فائق ؛ عام < النوع الفرعي > عام فرعي ؛

سيؤدي ذلك إلى قيام المترجم بالإبلاغ عن أخطاء التحويل لكل من عمليات التحويل (Generic<Subtype>)superGenericو (Generic<Supertype>)subGeneric.

يمكن تخفيف هذا التعارض باستخدام الحرف العام إذا ?تم استخدامه كمعامل نوع فعلي. [ 2 ]Generic<?> هو نوع فائق لجميع معاملات النوع العام . يسمح هذا بتعيين Genericكائنات من النوعين Generic<Supertype>بأمان إلى متغير أو معامل دالة من النوع . [ 2 ] يتيح استخدام نفس الشيء، مع تقييد التوافق مع النوع وأبنائه. [ 5 ] هناك احتمال آخر وهو ، الذي يقبل أيضًا كلا الكائنين ويقيد التوافق مع النوع وجميع آبائه. [ 5 ]Generic<Subtype>Generic<?>Generic<?extendsSupertype>SupertypeGeneric<?superSubtype>Subtype

نوع المعامل Wildcard

في جسم وحدة عامة، يُعامل مُعامل النوع (الرسمي) كما لو كان حده الأعلى (المُعبَّر عنه بـ extends; java.lang.Objectإذا لم يكن مُقيدًا). ​​[ 5 ] إذا كان نوع الإرجاع لدالة ما هو مُعامل النوع، ?فيمكن الإشارة إلى النتيجة (مثلًا من النوع ) بواسطة متغير من نوع الحد الأعلى (أو java.lang.Object). في الاتجاه الآخر، لا يُناسب الحرف البديل أي نوع آخر، ولا حتى java.lang.Object: إذا ?تم تطبيق كمُعامل نوع رسمي لدالة ما، فلا يُمكن تمرير أي مُعاملات فعلية إليها. ومع ذلك، يُمكن قراءة كائنات من النوع غير المعروف من الكائن العام وتعيينها إلى متغير من نوع فائق للحد الأعلى.

نموذج التعليمات البرمجية للفئة :Generic<TextendsUpperBound>

class Generic < T extends UpperBound > { private T t ;public Generic ( T t ) { this . t = t ; }public void set ( T t ) { this . t = t ; }public T get () { return t ; } }

نموذج كود يستخدم الفئة:Generic<TextendsUpperBound>

Generic <UpperBound> concreteTypeReference = new Generic <> (); Generic < ?> wildcardReference = concreteTypeReference ; UpperBound ub = wildcardReference.get ( ); // Object would also be OKwildcardReference.set ( new Object ()); // خطأ في النوع wildcardReference.set ( new UpperBound ( ) ); // خطأ في النوع concreteTypeReference.set ( new UpperBound ( ) ) ; // صحيح

أحرف البدل المحدودة

الحرف البديل المحدود هو حرف له قيد وراثي إما أعلى أو أدنى . يمكن أن يكون حد الحرف البديل نوع فئة، أو نوع واجهة ، أو نوع مصفوفة، أو متغير نوع . تُعبّر extendsالحدود العليا باستخدام الكلمة superالمفتاحية `< ...

الحدود العليا

يجب أن يكون الحد الأعلى لرمز البدل نوعًا فرعيًا من الحد الأعلى لمعامل النوع المقابل المُعلن عنه في النوع العام المقابل. [ 5 ] مثال على رمز بدل ينص صراحةً على حد أعلى هوGeneric<?extendsSubtypeOfUpperBound>referenceConstrainedFromAbove;

يمكن لهذا المرجع أن يحتوي على أي نوع من أنواع Genericالمعاملات التي يكون وسيطها من نوع فرعي من النوع SubtypeOfUpperBound. إن استخدام رمز بدل لا يحدد حدًا أعلى بشكل صريح يُعدّ بمثابة استخدام رمز بدل يحتوي على القيد ، لأن جميع أنواع المراجع في جافا هي أنواع فرعية من .extendsObjectjava.lang.Object

الحدود الدنيا

رمز بديل بحد أدنى، مثلGeneric<?superSubtypeOfUpperBound>referenceConstrainedFromBelow;

يمكن أن يحتوي على أي معلمات Genericيكون أي وسيط من نوع معين فيها نوعًا فرعيًا من الحد الأعلى لمعلمة النوع المقابلة ونوعًا فائقًا لـ SubtypeOfUpperBound. [ 5 ]

إنشاء كائن باستخدام أحرف البدل

لا يُسمح بإنشاء كائنات باستخدام وسيط نوع عام (مثلاً، ` <type>`). عمليًا، هذا غير ضروري، لأنه إذا أراد المستخدم إنشاء كائن يمكن إسناده إلى متغير من النوع `<type>` ، فبإمكانه ببساطة استخدام أي نوع عشوائي (يقع ضمن قيود النوع العام، إن وُجد) كوسيط نوع.newGeneric<?>()Generic<?>

ومع ذلك، يُسمح بذلك، لأن الحرف العام ليس مُعاملاً للنوع المُنشأ . وينطبق الأمر نفسه على .newArrayList<Generic<?>>()java.lang.ArrayList<E>newArrayList<List<?>>()

في تعبير إنشاء مصفوفة، يجب أن يكون نوع مكون المصفوفة قابلاً للتجسيد وفقًا لمواصفات لغة جافا، القسم 4.7. وهذا يعني أنه إذا كان لنوع مكون المصفوفة أي وسيطات نوع، فيجب أن تكون جميعها أحرفًا بدلًا غير محدودة (أحرف بدل تتكون من حرف واحد فقط ?). على سبيل المثال، `<<<>>` صحيح، بينما `<<<>>` غير صحيح.newGeneric<?>[20]newGeneric<SomeType>[20]

في كلتا الحالتين، يُعدّ عدم استخدام أي معلمات خيارًا آخر. سيؤدي هذا إلى ظهور تحذير لأنه أقل أمانًا من حيث النوع (انظر النوع الخام ).

مثال

في إطار عمل مجموعات جافا ، يُمثل الصنف java.util.List<E>مجموعة مُرتبة من الكائنات من النوع E. يتم تحديد الحدود العليا باستخدام extends: هي قائمة من الكائنات من فئة فرعية من ، أي أن أي كائن في القائمة مضمون أن يكون من النوع ، لذلك يمكن التكرار عليه باستخدام متغير من النوع [ 6 ].List<?extendsMyClass>MyClassMyClassMyClass

استيراد java.util.List ;public void doSomething ( List <? extends MyClass > list ) { for ( MyClass object : list ) { // OK // do something } }

ومع ذلك، ليس من المؤكد إمكانية إضافة أي كائن من هذا النوع MyClassإلى تلك القائمة:

استيراد java.util.List ;public void doSomething ( List <? extends MyClass > list ) { MyClass m = new MyClass (); list . add ( m ); // خطأ في الترجمة }

وينطبق العكس على الحدود الدنيا، والتي يتم تحديدها باستخدام super: A هي قائمة من الكائنات من فئة فائقة معينة ، أي أن القائمة مضمونة بأنها قادرة على احتواء أي كائن من النوع ، لذلك يمكن إضافة أي كائن من النوع :List<?superMyClass>MyClassMyClassMyClass

استيراد java.util.List ;public void doSomething ( List <? super MyClass > list ) { MyClass m = new MyClass (); list . add ( m ); // OK }

ومع ذلك، ليس من المؤكد إمكانية التكرار على تلك القائمة باستخدام متغير من النوع MyClass:

استيراد java.util.List ;public void doSomething ( List <? super MyClass > list ) { for ( MyClass object : list ) { // خطأ في الترجمة // قم بتنفيذ شيء ما } }

لكي نتمكن من القيام بكل من إضافة كائنات من النوع MyClassإلى القائمة والتكرار عليها باستخدام متغير من النوع MyClass، List<MyClass>يلزم وجود ، وهو النوع الوحيد من Listالذي يكون كلاً من و .List<?extendsMyClass>List<?superMyClass>

تُقدّم الاختصارات PECS (المنتج يمتد، المستهلك فائق) من كتاب Effective Java لجوشوا بلوخ طريقة سهلة لتذكر متى يجب استخدام الأحرف البديلة (المقابلة للتباين المشترك والتباين العكسي) في لغة جافا. [ 5 ]

قيود النوع في لغات أخرى

أقرب ميزة مكافئة لمعاملات أنواع الأحرف البديلة في جافا هي أحرف النوع البديلة في سكالا ؛ ويُشار إليها أيضًا باستخدام ?منذ سكالا 3 (في سكالا 2، كانت تُشار إليها بـ _). [ 7 ] تعمل حدود سكالا مثل حدود جافا: مكافئة لـ ، بينما مكافئة لـ .List[?<:Number]List<?extendsNumber>List[?>:Integer]List<?superInteger>

في لغة C++ ، يمكن التعبير عن قيود النوع العامة باستخدام المفاهيم . [ 8 ]

استيراد std ؛باستخدام std :: derived_from ؛ باستخدام std :: vector ؛class Player { // ... };// يجب أن يكون T نوعًا يكون الحد الأعلى للوراثة فيه هو Player، // مما يمنع أي نوع لا يرث من Player template < derived_from < Player > T > void processListOfPlayers ( const vector < T >& players ) { // ... }

هذا المثال يعادل كود جافا التالي:

استيراد java.util.List ;class Player { // ... }public class Example { // T مقيدة بالأنواع التي ترث من Player public static < T extends Player > void processListOfPlayers ( List < T > players ) { // ... } }

في لغة C# ، يمكن تمثيل حدود الأنواع باستخدام `<type>` و`< type>` (مقارنةً بلغة Java و`<type >` على التوالي)، بينما يُعبَّر عن قيد النوع العام باستخدام عبارة `<type>`. هذه العبارات أكثر تعبيرًا وقوة من الأحرف البديلة في Java. [ 9 ]X<outT>X<inT>X<?extendsT>X<?superT>where

باستخدام النظام ؛public class MyGenericClass < T , U > where T : IComparable <T> , allows ref struct where U : class , notnull , new ( ) { // ... }

على الرغم من أن لغة Kotlin هي أيضًا لغة JVM، إلا أنها لا تدعم أحرف البدل في أنواع البيانات على غرار Java. ومع ذلك، فهي تمثل أنواع البيانات ?على النحو التالي *(على سبيل المثال، List<*>)، بالإضافة إلى حدود الأنواع على النحو التالي و (مقارنةً بـ Java و على التوالي). فيما عدا ذلك، فهي تحتوي على عبارات على غرار C# : [ 10 ]X<outT>X<inT>X<?extendsT>X<?superT>where

دالة <T> copyWhenGreater ( list : List <T> , threshold : T ) : List <String> where T : CharSequence , T : Comparable <T> { return list.filter { it > threshold } .map { it.toString ( ) } }

تستخدم لغة Rustwhere أيضًا عبارات لربط السمات.

استخدم std :: cmp :: Ord ;struct MyStruct <T> where T : Ord + Default { value : T }impl <T> MyStruct <T> where T : Ord + Default { fn new ( value : T ) - > Self { MyStruct { value } }fn is_less_than ( & self , other : & Self ) -> bool { self . value < other . value } }

انظر أيضاً

الاقتباسات

  1. "الفصل 4. الأنواع والقيم والمتغيرات" . docs.oracle.com . تم الاطلاع عليه بتاريخ 2020-11-03 .
  2. 1 2 3 4 5 Bloch 2018 ، ص 117-122 ، الفصل §5 البند 26: لا تستخدم الأنواع الخام.
  3. جلعاد براخا (يونيو 2004)، "4. الأحرف البديلة"، البرمجة العامة في لغة جافا (ملف PDF) ، تم الاطلاع عليه في 6 مارس 2016
  4. "8.1.2 الفئات العامة ومعاملات النوع"، مواصفات لغة جافا ، أوراكل ، تم الاطلاع عليه في 6 مارس 2016
  5. 1 2 3 4 5 6 Bloch 2018 ، ص 139-145 ، الفصل §5 البند 31: استخدم الأحرف البديلة المحدودة لزيادة مرونة واجهة برمجة التطبيقات.
  6. الوراثة (البرمجة الكائنية التوجه)
  7. scala-lang.org (28 مايو 2026). "الوسائط البديلة في الأنواع" . docs.scala-lang.org . scala-lang.org.
  8. cppreference.com (6 يونيو 2026). "القيود والمفاهيم" . cppreference.com . cppreference.com.
  9. "حيث (قيد النوع العام)" . learn.microsoft.com . مايكروسوفت ليرن. 30 يوليو 2024.
  10. "الأنواع العامة: في، خارج، أين في كوتلين" . kotlinlang.org . JetBrains sro . تم ​​الاطلاع عليه بتاريخ 15 أكتوبر 2025 .

مراجع