تم شرح أدوية جافا بشكل مختصر مع الأمثلة

يرجى الاطلاع على هذه الأسئلة الشائعة لمزيد من المعلومات:

http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html#SECTION1

فيما يلي بعض النقاط المهمة من هذه الأسئلة الشائعة باختصار.

مثال (من الحور العام):

زوج الطبقة<X،Y> { 
  الخاص X أولاً؛
  خاص Y ثانية؛   الزوج العام (X a1، Y a2) {
    الأول = أ1؛
    الثانية = a2؛
  }
  public X getFirst() { return first; }
  public Y getSecond() { return Second; }
  public void setFirst(X arg)  { first = arg; }
  public void setSecond(Y arg) { Second = arg; }
}

الفصل زوج لديه نوعين من المعلمات X و ي .  يتم استبدالها بوسائط النوع عندما يكون النوع العام زوج تم إنشاء مثيل له. على سبيل المثال، في الإعلان زوج<سلسلة، تاريخ> معلمة النوع X يتم استبداله بوسيطة النوع خيط و ي يتم استبداله ب  تاريخ .
دونك المعرفات X و ي يكون التعريف الكامل للفئة.  في هذا النطاق معلمات النوعين X و ي يتم استخدامها كما لو كانت أنواعًا (مع بعض القيود). في المثال أعلاه، يتم استخدام المعلمات من أجل رشيتة ونوّع تعليقة لطرق المثيل و نيوس يكتنف المثيل.
عن المعلمة الحور بحدود يمكن الإعلان عنها. تتيح الحدود الوصول إلى أساليب المعلم المجهول. في مثالنا، لا نستدعي أي طرق من أنواع غير معروفة X و ي . ولهذا السبب المعلمات فانات الحورين غير ممتع.

مثال

زوج طباعة الفراغ العام ( زوج <String، Long> زوج) {
  System.out.println("("+pair.getFirst()+"،"+pair.getSecond()+")");
} زوج <String، Long> الحد = جديد زوج <String، Long> ("الحد الأقصى"، 1024 لتر)؛
printPair(limit);

مثال (لنوع معلمات حرف البدل):

زوج طباعة الفراغ العام ( زوج<؟،؟> زوج) {
  System.out.println("("+pair.getFirst()+"،"+pair.getSecond()+")");
} زوج<؟،؟> الحد = جديد زوج <String، Long> ("الحد الأقصى"، 1024 لتر)؛
printPair(limit);

تشترك جميع عمليات إنشاء النوع العام في نفس تمثيل نوع وقت التشغيل، أي تمثيل النوع الخام. على سبيل المثال، إنشاءات النوع العام قائمة ، مثل قائمة<Date> , قائمة<String> , قائمة<Long> وما إلى ذلك لها أنواع ثابتة مختلفة في وقت الترجمة، ولكن نفس النوع الديناميكي قائمة أثناء العملية.

يتكون طاقم الممثلين من جزأين:

  • فحص النوع الثابت الذي يقوم به المترجم في وقت الترجمة و
  • فحص النوع الديناميكي الذي يتم إجراؤه بواسطة الجهاز الظاهري في وقت التشغيل.

يقوم الجزء الثابت بفرز القوالب غير المنطقية، التي لا يمكن أن تنجح، مثل القوالب من خيط الدي – التي تاريخ أو من قائمة<String> الدي – التي قائمة<Date> .

يستخدم الجزء الديناميكي من نوع المعلومات في وقت التشغيل ويقوم بإجراء فحص للنوع في وقت التشغيل.  ويتير ا ClassCastException إذا كان النوع الديناميكي للكائن ليس هو النوع الهدف (أو نوع فرعي من النوع الهدف) من طاقم الممثلين. من أمثلة القوالب ذات الجزء الديناميكي القوالب من هدف الدي – التي خيط أو من هدف الدي – التي قائمة<String> .  إنهم هم ما يسمى بالمنبوضين، من الفيق الفيق إلى الأفق.

أمثلة على أنواع المعلمين قائمة<String> , Map<String،Date> ولكن لا قائمة<؟ يمتد Number> أو Map<String،؟ > .

وإلى عرض المزيد قائمة<Object> سيكون نوعًا فائقًا من أ قائمة<String> ، لأن هدف هو نوع فائق من خيط .  ينبع هذا التوقع من حقيقة وجود مثل هذا النوع من العلاقة للمصفوفات:  هدف[] هو نوع فائق من خيط[] ، لأن هدف هو نوع فائق من خيط . (يُعرف هذا النوع من العلاقات باسم التغاير .) تمتد علاقة النوع الفرعي الفائق لأنواع المكونات إلى أنواع المصفوفات المقابلة. لا توجد مثل هذه العلاقة النوعية لإنشاء مثيلات الأنواع العامة. (الأنواع ذات المعلمات هي لا عامل.)

إن عدم وجود علاقة من النوع العام له عواقب مختلفة.  هنا مثال.

مثال:

طباعة باطلة الكل (ArrayList<Object> ج) {
  لـ (الكائن س: ج) 
    System.out.println(o);
} ArrayList<String> list = new ArrayList<String>();
...ملء القائمة...
printAll(list);   // خطأ

أ ArrayList<String> لا يمكن تمرير الكائن كوسيطة إلى الطريقة التي تطلب a ArrayList<Object> لأن النوعين عبارة عن مثيلات من نفس النوع العام، ولكن ل مختلف والسيتات الأكثر شيوعًا، ولهذا السبب فهي غير متوافقة مع بعضها البعض.

أنواع المعلمين هي إصدارات المعلمين.  هم سيارة ميتل جديدة; لا يوجد سوى عدد قليل من القيود.  ولا يمكن استخدامه للأغراض التالية:

  • لإنشاء المصفوفات
  • في معالجة الاستثناء
  • في الصف الحرفي
  • في مثيل تعبير

المصفوفات التي تحتوي على العناصر هي من النوع الذي يحدده المعلمون غير القانونيين.

مثال (لنوع الصفيف غير القنوني):

اختبار الفراغ الثابت () {
  زوج<عدد صحيح،عدد صحيح>[] intPairArr = new زوج<عدد صحيح، عدد صحيح>[10] ; // خطأ
  addElements(intPairArr); 
  Pair<Integer,Integer> Pair = intPairArr[1];
  عدد صحيح i = Pair.getFirst();
  Pair.setSecond(i);
}
عناصر إضافية باطلة ثابتة ( هدف[] أوبجر) {
  objArr[0] = new Pair<Integer,Integer>(0,0);
  objArr[1] = new Pair<String,String>(""،");      // يجب أن يفشل مع ArrayStoreException
}

يحظر المترجم إنشاء صفائف يكون نوع مكوناتها نوعًا محددًا ذي معلمات محددة، مثل زوج<عدد صحيح، عدد صحيح> في مثالنا.  لقد ناقشنا في الإدخال السابق لماذا من المعقول أن يكون المترجم مؤهلاً لـ زوج<عدد صحيح،عدد صحيح>[] باعتبارها غير قانونية.  المشكلة الأساسية هي أن المترجم ونظام وقت التشغيل يجب أن يتأكدوا من أن المصفوفة هي متجانس تسلسل العناصر من نفس النوع.  أحد عمليات التحقق من النوع، وهو فحص مخزن المصفوفة الذي يتم إجراؤه بواسطة الجهاز الظاهري في وقت التشغيل، يفشل في اكتشاف الإدراج المخالف لعنصر غريب. في المثال الإدراج الثاني في addElements يجب أن تفشل الطريقة، لأنها كانت تضيف زوجين من السلاسل إلى العش، لكنها لم تفشل كما كان متوقعا. وقد تمت مناقشة الأسباب في الإدخال السابق.

إذا لم نتمكن من استخدام المصفوفات التي تحتوي على عناصر من نوع معين مع المعلمات، فماذا نستخدم كبديل؟

دعونا نفكر في 3 حلول يمكن تصورها:

  • مجموعة من الأنواع الخام
  • مجموعة من نوع معلمات بدل غير محدود
  • جمع بدلا من المصفوفة

في ذلك المسفوفات الجديدة آست المعلمات الخرسانية غير العربية، آلا إلى عمل البرامج الجديدة آست المعلمات الخرسانية.

نوع معلمي الحرف البديل هو مثال للنوع الشائع حيث يكون النوع المتوسط ​​على الأقل تعبيراً عن الحرف البديل.  أمثلة على أنواع المعلمين البديلين هي مجموعة<؟ > , قائمة<؟ يمتد Number> , المقارنة<؟ سوبر String> و زوج<String،؟ > . يشير نوع معلمات حرف البدل إلى عائلة من الأنواع تشتمل على مثيلات ملموسة لنوع عام.  يحدد نوع حرف البدل المستخدم أنواع المعلمات الملموسة التي تنتمي إلى العائلة.  على سبيل المثال، نوع معلمة حرف البدل مجموعة<؟ > يدل على عائلة جميع مثيلات مجموعة الواجهة بغض النظر عن وسيطة النوع.  نوع معلمة حرف البدل قائمة<؟ يمتد Number> تشير إلى عائلة جميع أنواع القائمة حيث يكون نوع العنصر نوعًا فرعيًا منها  رقم .  نوع معلمة حرف البدل المقارنة<؟ سوبر String> هي عائلة جميع مثيلات المقارنة واجهة لأنواع وسيطة النوع التي تعد أنواعًا فائقة خيط.

نوع حرف البدل ذو معلمات ليس نوعًا بالمعنى العادي (يختلف عن فئة/واجهة غير ذات معلمات أو نوع خام).

يمكن استخدام أنواع معلمات Wildcard للكتابة (مثل الفئات والواجهات غير ذات المعلمات):

  • كوسيطة وأنواع الإرجاع من الأساليب
  • كنوع حقل أو متغير مرجعي محلي
  • كنوع مكون من وسيطة نوع المصفوفة لأنواع ذات معلمات أخرى
  • كنوع الهدف في القوالب

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

هنا مثال عام الأعلى طريقة لحساب القيمة الأكبر في مجموعة من العناصر ذات النوع غير المعروف أ .

مثال (لطريقة عامة):

مجموعات الصف {
  ساكنة عامة يمتد <A للمقارنة<A>> A ماكس (مجموعة < أ > xs) {
    مكرر< أ > xi = xs.iterator();
    أ w = xi.next();
    بينما (xi.hasNext()) {
      أ x = xi.next();
      if (w.compareTo(x) < 0) w = x;
    }
    العودة ث؛
  }
} 

ال الأعلى الأسلوب لديه معلمة نوع واحد، اسمه أ .  إنه مكان لنوع عنصر المجموعة الذي تعمل عليه الطريقة. معلمة النوع لها حد؛ يجب أن يكون نوعًا يمثل نوعًا فرعيًا من قابل للمقارنة<A>

مثال (من نفس النوع العام، هذه المرة مع الحدود):

الواجهة العامة القابلة للمقارنة<T> {
  public int CompareTo(T arg);
}
الفئة العامة TreeMap<Key يمتد Comparable<Key> ,بيانات>{
  إدخال فئة ثابتة خاصة<K,V> {
     مفتاح K؛
     قيمة الخامس؛
     Entry<K,V> left = null;
     Entry<K,V> right = null;
     إدخال<K،V> الأصل؛
  }
  Entry<Key الخاص العابر,Data> root = null;
  ...
  دخول خاص<Key،Data> getEntry(مفتاح المفتاح) {
     Entry<Key,Data> p = root;
     مفتاح ك = مفتاح؛
     بينما (ص ! = فارغة) {
       كثافة العمليات = ك. قارن إلى(p.key) ; 
       إذا (cmp == 0)
         العودة ص؛
       وإلا إذا (cmp < 0)
         ع = ص. يسار;
       آخر 
         ع = ص. يمين؛ 
     }
     عودة فارغة؛
  }
  منطقية عامة تحتوي على مفتاح (مفتاح المفتاح) {
     return getEntry(key) != null;
  }
  ...
}

في المثال أعلاه، معلمة النوع مفتاح لديه الحد قابلة للمقارنة <Key> .  تحديد الحد له تأثيران:

  • فهو يتيح الوصول إلى الأساليب التي يحددها المنضم .  في المثال، الحد قابلة للمقارنة <Key> يتيح الوصول إلى قارن إلى الطريقة التي نريد الاحتجاج بها في تنفيذ لدينا خريطة الشجرة فصل.
  • يمكن استخدام الأنواع “ ضمن قيود ” فقط لإنشاء نموذج للنوع العام.   في المثال، نوع ذو معلمات مثل TreeMap<Number،String> سيتم رفضه، لأن النوع رقم ليس نوعًا فرعيًا من قابل للمقارنة<الرقم> .  نوع ذو معلمات مثل TreeMap<String,String> سيتم قبوله، لأن نوع السلسلة يقع ضمن الحدود، أي نوع فرعي من قابلة للمقارنة<String> .

يمكن استخدام جميع الفئات والواجهات وأنواع التعداد كمعلمات نوع مرتبطة، بما في ذلك الأنواع المتداخلة والداخلية.  لا يتم دخولها للمسفورة لمعلمة مقاومة للماء.

أمثلة:

يمتد الفصل X0 <T كثافة العمليات أوزيكس0ز {...}      // خطأ
يمتد الفصل X1 <T هدف[] أوزيكس0ز {...} // خطأ
يمتد الفصل X2 <T رقم أوزيكس0ز {...}
تمتد الفئة X3 <T خيط أوزيكس0ز {...}
تمتد الفئة X4 <T قابل للتشغيل أوزيكس0ز {...}
تمتد الفئة X5 <T Thread.State أوزيكس0ز {...}
تمتد الفئة X6 <T قائمة أوزيكس0ز {...}
تمتد الفئة X7 <T قائمة<String> أوزيكس0ز {...}
تمتد الفئة X8 <T قائمة<؟ يمتد Number> أوزيكس0ز {...}
يمتد الفصل X9 <T مقارنة <؟ الرقم الفائق > أوزيكس0ز {...}
يمتد الفصل X10<T Map.Entry<؟،؟> أوزيكس0ز {...}

يوضح نموذج التعليمات البرمجية أن الأنواع البدائية مثل كثافة العمليات وأنواع المصفوفات مثل هدف[] غير مفيدة كمعلمة نوع منزمة.

تيوود الفوسل رقم أو خيط وأنواع الواجهة، مثل قابل للتشغيل , بها كمعلمة نوع منزمة.

تقديم المتعددة Thread.State مسموح بها أيضًا كمعلمة نوع منضمة. Thread.State إنه مثال على النوع المتداخل المستخدم كمدرس.  ,

لتكتشف باليوس العلوامة إناثا منزمة لمعلمة الإطور؛ قائمة هو مثال.

لتولو بليوس آست المعلمات كنوع منزل لمعلمات، بما في ذلك في تولو بليوس آست المعلمات تعليق قائمة<String> ، أنواع معلمات أحرف البدل المحددة مثل قائمة<؟ يمتد Number> و مقارنة <؟ سوبر Long> وأنواع معلمات أحرف البدل غير المحدودة مثل Map.Entry<؟،؟> .  يسمح بالاتصال الذي هو نوع معلمات المحول باستخدام مفتاح التبديل لجميع الأنواع المرتبطة بعائلة المحول المشار إليها بواسطة حرف التبديل.  يعطي نوع المعلمين حرف البدل وصلاً مقيدًا قطعًا إلى التوفيق والإذاء؛ القيود تعتمد على نوع حرف البدل.

مثال

فئة X< T يمتد List<؟ يمتد Number> أوزيكس0ز {
  الفراغ العام someMethod(T t) {
    t.add(new Long(0L));    // خطأ
    الرقم ن = t.remove(0);
  }
}
اختبار الصف {
  public static void main(String[] args) {
     X<ArrayList< طويل >> x1 = new X<ArrayList<Long>>(); 
     X<ArrayList< خيط >> x2 = new X<ArrayList<String>>(); // خطأ
  }
}

المتغيرات المرجعية من النوع ت يتم التعامل مع (معلمة الإبدل) كمتغير مرجعي لنوع حرف التغيير (معلمة الإبدل العربية).  في مثالنا النتيجة هي أن المترجم يرفض استدعاء الأساليب التي تأخذ وسيطا من النوع “، المجهول ” الذي يمثل معلم النوع، مثل قائمة.إضافة , لان الحد هو نوع ذ المعلمات بدل مع حد على حده.
وفي نفس الوقت قائمة<؟ يمتد Number> يحدد الأنواع التي يمكن استخدامها كوسائط للنوع. يقبل المترجم جميع وسائط النوع التي تنتمي إلى عائلة النوع قائمة<؟ يمتد Number> ، أي جميع الأنواع الفرعية قائمة مع وسيطة النوع التي تعد نوعًا فرعيًا من رقم .

يمكن تعيين مدرس من النوع كمدرس من نوع آخر.

مثال

فئة ثلاثية <T> {
  خاص T fst، snd، trd؛
  < العام ش يمتد T , V يمتد T , دبليو يمتد T > Triple(U arg1, V arg2, W arg3) {
    fst = arg1;
    snd = arg2;
    trd = arg3;
  }
}

في هذا المثال معلمة النوع ت يتم استخدام الفئة ذات المعلمات كربط لمعلمات النوع ش ,  V و دبليو لطريقة المثيل آست المعلمات.

يتضمن الفرص الإضافية لاستخدام معلمة النوع كحدود لمعلمات النوع الأخرى في المواقف التي يتم فيها تعريف نوع متداخل ضمن نوع عام أو يتم تعريف فئة محلية ضمن طريقة عامة.  يُسمح أيضًا باستخدام معلم المعلم كرابط لمعلم معلم آخر في نفس فئة معلم المعلم.

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

مثال

الطبقة العامة سوبر كلاس {     // الأعضاء الثابتة
    التعداد العام EnumType {THIS، THAT}
    كائن ثابت عام staticField؛
    public static void staticMethod() { ... }

    // أعضاء غير ثابتين
    الطبقة العامة InnerClass {...}
    كائن عام غير ثابت؛
    الفراغ العام غير StaticMethod () { ... }

    // المنشئون
    فئة SuperClass العامة () { ... }

    // الأعضاء الخاصين
    كائن خاص حقل خاص؛ 

    ...
}

يمتد الفصل النهائي العام SomeClass<T سوبر كلاس أوزيكس0ز {
    كائن T الخاص؛
    public SomeClass(T t) { object = t; } 

    سلسلة عامة إلى سلسلة () {
        يعود
         "نوع متداخل ثابت    : "+T.EnumType.class+"\n" 
        +"حقل ثابت          : "+T.staticField+"\n"
        +"طريقة ثابتة         : "+T.staticMethod()+"\n"
        +"نوع متداخل غير ثابت: "+T.InnerClass.class+"\n"
        +"حقل غير ثابت      : "+object.nonStaticField+"\n"
        +"طريقة غير ثابتة     : "+object.nonStaticMethod()+"\n"
        +"constructor           : "+(new T())+"\n"                    // خطأ
        +"عضو خاص        : "+object.privateField+"\n"          // خطأ 
        ;
    }
}

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

السياق Enum<E يمتد Enum<E>> “يذهر هو إعلان التعداد فئة في الحزمة java.lang :

فئة مجردة عامة Enum<E يمتد Enum<E>> {
  ...
}

النوع التعداد هي الفئة الأساسية المشتركة لجميع أنواع التعداد.  في جافا نوع التعداد مثل لون يتم ترجمتها إلى فئة لون الذي يمتد التعداد<اللون> . الغرض من الطبقة المتفوقة التعداد ويوفر وظيفة مشتركة بين جميع أنواع العد.

هنا رسم للفصل التعداد :

فئة مجردة عامة إنوم< ه يمتد Enum<E>> تنفذ Comparable< ه >، قابل للتسلسل {
  اسم السلسلة النهائية الخاصة؛
  اسم السلسلة النهائية العامة () { ... }   الترتيب النهائي الخاص؛
  العام النهائي int الترتيبي () { ... }

  التعداد المحمي (اسم السلسلة، int الترتيبي) { ... }

  سلسلة عامة           toString() { ... }
  القيمة المنطقية النهائية العامة تساوي (كائن آخر) { ... }
  public Final int hashCode() { ... }
  استنساخ الكائن النهائي المحمي () يرمي CloneNotSupportedException { ... }
  int العام النهائي قارن إلى ( ه س) { ... }

  Class< النهائي العام ه > getDeclaringClass() { ... }
  يقوم <T الثابت العام بتوسيع Enum<T>> T valueOf (Class<T> enumType، String name) { ... }
}

ميزة السرعة في الدخول” Enum<E يمتد Enum<E>> ” هي فئة حديدية حديثة التعداد ومعلمة النوع المحددة حديثًا ه تظهر في حدود نفس معلمة النوع.  وهذا يعني أن التعداد يجب إنشاء مثيل للنوع لأحد أنواعه الفرعية.  من أجل فهم سبب منطقية ذلك، ضع في اعتبارك أن كل نوع من أنواع التعداد يتم ترجمته إلى نوع فرعي من التعداد .

هنا هو نوع العداد المفتح لون :

التعداد لون {الأحمر والأزرق والأخضر}

يقوم المترجم بترجمته إلى الفئة التالية:

الطبقة النهائية العامة لون يمتد التعداد<اللون> {
  اللون النهائي العام الثابت[] القيم() { return (Color[])$VALUES.clone(); }
  قيمة اللون الثابتة العامة (اسم السلسلة) { ... }   لون خاص (String s، int i) { super(s, i); }

  اللون النهائي العام الثابت أحمر؛
  اللون النهائي العام الثابت أزرق؛
  اللون النهائي العام الثابت أخضر؛

  اللون النهائي الثابت الخاص $VALUES[];

  ثابت {
    RED = لون جديد("RED"، 0);
    أزرق = لون جديد ("أزرق"، 1)؛
    GREEN = لون جديد("GREEN"، 2);
    $VALUES = (new Color[] { RED, BLUE, GREEN });
  }
}

الميراث له الأثر الذي لون النوع يرث جميع الطرق المطبقة في التعداد<اللون> .  ومن بينها قارن إلى طريقة.  ال لون. قارن إلى من المحتمل أن تستغرق الطريقة أ لون كحجة.  من أجل تحقيق هذا الصف التعداد هو عام و Enum.compareTo يأخذ الأسلوب التعداد معلمة النوع ه كحجة.  ونتيجة لذلك، اكتب لون مشتق من التعداد<اللون> يرث أ قارن إلى الطريقة التي تأخذ لون كما يجب أن تكون.
إذا قمنا بالإعلان عن “ Enum<E يمتد Enum<E>> “imcan هو نوع من التسليم الذي يتم إعادة إنتاجه.

أولاً، هناك حقيقة أن معلم الأنواع المرتبطة هو النوع نفسه: “ التعداد يمتد <E التعداد <E>> “. يتأكد من أن الأنواع الفرعية هي فقط من النوع التعداد مسموح بها كوسيطات نوع. (من الناحية النظرية، اكتب التعداد يمكن إنشاء مثيل لها على نفسها، كما هو الحال في إنوم<إنوم> ولكن هذا بالتأكيد غير مقصود ويصعب تصور موقف فيه مثل هذا).

ثانيًا، هناك حقيقة مفادها أن نوع المعلم المرتبط به هو نوع المعلم التعداد <E> ، والذي يستخدم معلمة النوع ه كوسيطة نوع الحد. يتأكد هذا الإعلان من أن علاقة الميراث بين النوع الفرعي وإنشاء مثيل له التعداد هو من النموذج X يمتد Enum<X> “. اكتب فرعيًا مثل “ X يمتد Enum<Y> “ لا يمكن التعبير عنه بسبب الوسيلة ي لن يكون ضمن الحدود؛ الأنواع الفرعية فقط من إنوم<X> فهو يقع ضمن الحدود.

ثالثا، هناك الحقيقة التعداد هو عام في المقام الأول.  وهذا يعني أن بعض أساليب الطبقة التعداد خذ وسيطة أو قم بإرجاع قيمة من نوع غير معروف (أو تعتمد على نوع غير معروف). وكما نعلم بالفعل، فإن هذا النوع غير المعروف سيصبح لاحقًا نوعًا فرعيًا X ل إنوم<X> .  وبالتالي، في نوع المعلمة إنوم<X> ، تتضمن هذه الأساليب النوع الفرعي X ، ويتم توريثها في النوع الفرعي X .  ال قارن إلى مثال على الرجع على الآلام; يتم تعريف توريثه من كلمة الفيقة لكل بركة في كل ستحة

وخالصة القول إن التصريح “ Enum<E يمتد Enum<E>> يمكن فك تشفير “ على النحو التالي: التعداد هو نوع عام لا يمكن إنشاء مثيل له إلا لأنواعه الفرعية، وسترث هذه الأنواع الفرعية بعض الطرق المفيدة، والتي يأخذ بعضها وسيطات محددة للنوع الفرعي (أو يعتمد على النوع الفرعي).

معلمات نوع الحد الأدنى للفئات

يمكن أن تحتوي معلمات النوع على عدة حدود، كما هو الحال في فئة Box<T تمتد Number> {...} . لكن معلمة النوع لا يمكن أن يكون لها حد أدنى، أي بناء مثل فئة Box<T عظيم رقم> {...} غير مشهور به ولم لا؟  الجواب: لا فائدة منه لأنه لن يشتري لك شيئاً إذا سمح بذلك.  دعونا نرى لماذا ستكونون معلمين لهذا النوع آتس الحد الحد لفعة مربكية من ذلك ما يعني العلامة التجارية في المعلمة الذهبية.

للمعلم ثلاثة آثار:

    1. مثيل مقيد. يقيد الحد العلوي مجموعة الأنواع التي يمكن استخدامها لإنشاء مثيل للنوع العام.  إذا أعلنا أ فئة Box<T تمتد Number> {...} ثم سيضمن المترجم أن الأنواع الفرعية فقط من رقم يمكن استخدامها كوسيطة نوع.  وهذا هو، أ صندوق<رقم> أو أ صندوق<Long> مسموح به، ولكن أ Box<Object> أو Box<String> سيتم رفضه

مثال (لإنشاء مثيل مقيد بسبب الحد الأعلى لمعلمة النوع):
يمتد فئة Box<T Number> { 
   قيمة T الخاصة؛ 
   صندوق عام (T t) { value = t؛ } 
   ...
}  اختبار الصف { 
   public static void main(String[] args) { 
       Box<Long> boxOfLong = new Box<Long>(0L);   // بخير
       Box<String> boxOfString = new Box<String>(""); // خطأ: السلسلة ليست ضمن الحدود
   }
}

  1. الوصول إلى الأعضاء غير الثابتة. يتيح الحد العلوي الوصول إلى جميع الأساليب العامة غير الثابتة وحقول الحد العلوي.  في تنفيذ لدينا فئة Box<T تمتد Number> {...} يمكننا استدعاء كافة الأساليب العامة غير الثابتة المحددة في الفصل رقم ، مثل قيمة int() على سبيل المثال.  بدون الحد الأعلى، سيرفض المترجم أي استدعاء من هذا القبيل. مثال (للوصول إلى الأعضاء غير الثابتين بسبب الحد الأعلى لمعلمة النوع):

يمتد فئة Box<T Number> { 
   قيمة T الخاصة؛ 
   صندوق عام (T t) { value = t؛ } 
   زيادة int العامة () {قيمة الإرجاع.intValue ()+1؛ } // <= سيكون خطأ بدون ربط الرقم
   ...
} 

    1. اكتب المحو. يتم استخدام الحد العلوي الموجود في أقصى اليسار لمحو النوع ويستبدل معلمة النوع في رمز البايت.  في لدينا فئة Box<T تمتد Number> {...} جميع حوادث ت سيتم استبداله بالحد الأعلى رقم .  على سبيل المثال، إذا كان الصف صندوق لديه حقل خاص من النوع ت وطريقة مجموعة باطلة (محتوى T) لتعيين هذا الحقل الخاص، سيكون الحقل من النوع رقم بعد محو النوع وسيتم ترجمة الطريقة إلى طريقة مجموعة باطلة (محتوى الرقم) .

مثال قبل نوع المحو):
فئة Box< T يمتد الرقم أوزيكس0ز { 
   خاص ت قيمة؛ 
   الصندوق العام( ت ر) { القيمة = ر؛ } 
   ...
} 

      مثال

بعد

      نوع المحو):

 

صندوق الفئة { 
   خاص رقم قيمة؛ 
   الصندوق العام( رقم ر) { القيمة = ر؛ } 
   ...
}

    بالإضافة إلى ذلك، يظهر الحد العلوي الموجود في أقصى اليسار في مواقع أخرى، مثل القوالب وطرق الجسر المُدرجة تلقائيًا.

إذا تم السماح بالحدود الدنيا لمعلمات النوع، فما هي الآثار الجانبية التي قد تحدث أو ينبغي أن تحدث؟ إذا كان بناء مثل فئة Box<T عظيم رقم> {...} سومه، ماذا يعني ذلك؟  ماذا تقصد بالآثار الجانبية الثلاثة للمعلم؟

مثيلات مقيدة. يمكن للمترجم تقييد مجموعة الأنواع التي يمكن استخدامها لإنشاء مثيل للنوع العام بمعلمة نوع منضمة أقل.  على سبيل المثال، يمكن للمترجم أن يسمح بإنشاء مثيلات مثل صندوق<رقم> و Box<Object> من أ صندوق<T عظيم رقم> ورفض إنشاء مثيلات مثل صندوق<Long> أو صندوق<قصير> .  سيكون هذا تأثيرًا يتماشى مع التأثير الجانبي المقيد الموصوف لحدود معلمات النوع العلوي.

الوصول إلى الأعضاء غير الثابتة. لا يمنح حد معلمة النوع الأدنى إمكانية الوصول إلى أي أساليب معينة بخلاف تلك الموروثة من الفئة هدف . في مثال صندوق<T عظيم رقم> الأنواع الفائقة من رقم ليس لديهم أي شيء مشترك، إلا أنهم أنواع مرجعية وبالتالي أنواع فرعية من هدف .  لا يمكن للمترجم أن يفترض أن حقل النوع ت هو من النوع رقم أو نوع فرعي منها.  بدلاً من ذلك، حقل النوع ت يمكن أن يكون من أي نوع فائق رقم ، مثل قابل للتسلسل أو هدف .  استدعاء طريقة مثل قيمة int() لم يعد آمنًا للنوع وسيتعين على المترجم رفضه. ونتيجة لذلك، فإن الحد الأدنى من معلمة النوع لن يمنح الوصول إلى أعضاء غير ثابتين يتجاوز هؤلاء المحددين في الفئة هدف وبالتالي سيكون له نفس التأثير على “ كما هو الحال في ”.

اكتب المحو .  باتباع هذا الخط المنطقي، ليس من المنطقي استبدال تكرارات معلمة النوع بحدها الأدنى في أقصى اليسار.  الإعلان عن طريقة مثل المنشئ صندوق( ت ر) كمنشئ صندوق( رقم ر) لا معنى له، معتبرا ذلك ت يتم استبداله بنوع فائق من رقم .  ان هدف قد يتم تمريرها بحق إلى المنشئ في إنشاء مثيل Box<Object> وسوف يرفضه المنشئ.  وهذا من شأنه أن يكون خاطئا تماما.   لذا، فإن محو النوع سيحل محل جميع تكرارات متغير النوع ت حسب النوع هدف ، وليس أقلها.  مرة أخرى، سيكون له نفس تأثير “ بدون حدود ”.

هل يمكن أن يكون أكثر معرفًا لهذا هو كل شيء _و_ الحدود العليا لها?   أنا شخصياً لا أريد حتى التفكير في الأمر وأفضل أن أضعه ضمن فئة “unmanageable”، إذا أمكنني ذلك.

وخالصة القول هي: كل التون “ عظيم “الكود الذي ستشتريه هو الكود الذي يقتصر على الأنواع عالية الجودة فقط رقم يمكن استخدامها كوسيطات الكتابة.  وحتى هذا كثيرا ما يساء فهمه.  هذا لا يعني ذلك فئة Box<T الرقم الفائق> {...} يحتوي فقط على حالات من الأنواع الفائقة لـ رقم .  والعكس تماماً – كما هو موضح في المثال أدناه!

مثال قبل نوع المحو):

فئة Box< رقم سوبر أوزيكس0ز {
   خاص ت قيمة؛
   الصندوق العام( ت ر) { القيمة = ر؛ }
   ...
}

مثال بعد نوع المحو):

صندوق الفئة {
   خاص هدف قيمة؛
   الصندوق العام( هدف ر) { القيمة = ر؛ }
   ...
}

أ فئة Box<T عظيم رقم> {...} سيتم ترجمتها بواسطة محو النوع إلى a صندوق تحتوي على هدف سيتم ترجمة الحقل ومنشئه إلى الصندوق (الكائن ر) . وهذا يختلف جوهريا عن أ فئة Box<T يمتد رقم> {...} ، والتي سيتم ترجمتها إلى أ صندوق تحتوي على أ رقم سيتم ترجمة الحقل ومنشئه إلى صندوق (رقم ر) . وبناء على ذلك، أ صندوق<رقم> مثيل من أ فئة Box<T تمتد Number> {...} سيكون مختلفًا عن أ صندوق<رقم> مثيل من أ فئة Box<T الرقم الفائق> {...} , وهو ما من ساعنه أن قاعدة العرتباك.  ولهذا السبب فان الحدون الدنيا لا معنى لها في المعلمة الحور لفيات.

 


 

معلمات نوع الحد الأدنى للطرق

بالتزامن مع أساليب وأنواع الوسائط، قد تتمكن من تعليم النوع الذي يكون مفيدًا إلى حد ما في بعض الحالات.

مثال

زوج الطبقة<X،Y> {
   الخاص X أولاً؛
   خاص Y ثانية؛
   ...
   < العام سوبر اكس , ب سوبر ي > B addToMap(Map<A,B> Map) { // خطأ: لا يمكن أن تحتوي معلمة النوع على حد أدنى
      إرجاع Map.put(first, Second);
   }
}
اختبار الصف { 
   public static void main(String[] args) { 
     Pair<String,Long> زوج = زوج جديد<>("ABC",42L);
     Map<CharSequence, Number> Map = HashMap<CharSequence, Number>();
     رقم الرقم = زوج.addToMap(map);
   }
}

ال addToMap() تضيف الطريقة محتوى الزوج إلى الخريطة.  أي خريطة يمكنها استيعاب أنواع فائقة من X و ي سوف تفعل.  الخريطة يضع() تُرجع الطريقة القيمة الموجودة في الخريطة للمفتاح المحدد، إذا كان هناك بالفعل إدخال قيمة مفتاح للمفتاح في الخريطة.  القيمة المرجعة للخريطة يضع() يجب إرجاع الطريقة من addToMap() طريقة.  في ظل هذه الظروف، يرغب المرء في الإعلان عن الطريقة كما هو موضح أعلاه: يتم تحديد معلمات الخريطة باستخدام أنواع فائقة من معلمات نوع الزوج و addToMap() نوع الإرجاع هو نوع قيمة الخريطة.

ولأن المترجم لا يسمح بحدود معلمي هذا النوع، فإننا بحاجة إلى حل بديل.

ومن الحلول التي تتبادر إلى الذهن هو توظيف خطاب التبادل، لأن خطاب التبادل يمكن أن يكون له حد أدنى.  فيما يلي بديل حرف البدل.

مثال

زوج الطبقة<X،Y> {
   الخاص X أولاً؛
   خاص Y ثانية؛
   ...
   عام هدف addToMap(Map< ؟ سوبر اكس , ؟ سوبر ي خريطة >) { 
      إرجاع Map.put(first, Second);
   }
}
اختبار الصف { 
   public static void main(String[] args) { 
     Pair<String,Long> زوج = زوج جديد<>("ABC",42L);
     Map<CharSequence, Number> Map = HashMap<CharSequence, Number>();
     رقم الرقم = (رقم) Pair.addToMap(map);
   }
}

إنه يعمل، إلا أنه لا توجد طريقة للإعلان عن نوع الإرجاع حسب الرغبة.  سيكون من النوع الفائق ي والتي يلتقطها المترجم من نوع الخريطة، ولكن لا توجد بنية جملة لتعريفها.  من أجل ألا نفل إنفون ألفايتا “” ؟ سوبر ي “، لان “ ؟ سوبر ي ” هو بديل للأحرف وليس نوعًا، لذا فهو لا يسمح بإعادته. ليس لدينا خيار ويجب استخدامه هدف بدلاً من ذلك كنوع الإرجاع لطريقتنا.  وهذا النوع غير المحدد من الإرجاع بدوره يفرض على المتصلين بـ addToMap() طريقة لطرح قيمة الإرجاع لأسفل من هدف إلى الحقيقي.  وهذا ليس بالضبط ما كان يدور في أذهاننا.

الحل الآخر هو استخدام أساليب ثابتة.  إليك حل بديل باستخدام طريقة ثابتة بدلاً من الطريقة غير الثابتة.

مثال (لبديل للمثال السابق باستخدام طريقة ثابتة):

زوج الطبقة<X،Y> {
   الخاص X أولاً؛
   خاص Y ثانية؛
   ...
   عام ثابت < أ , ب ،X يمتد أ ، ي يمتد ب > B addToMap (Pair<X، زوج Y>، Map< أ , ب خريطة >) {
      إرجاع Map.put(pair.first,pair.sec);
   }
}
اختبار الصف { 
   public static void main(String[] args) { 
     Pair<String,Long> زوج = زوج جديد<>("ABC",42L);
     Map<CharSequence, Number> Map = HashMap<CharSequence, Number>();
     رقم الرقم = زوج .addToMap( زوج ،رسم خريطة)؛
   }
}

العام addToMap() تحتوي الطريقة على أربع معلمات من النوع: عنصران نائبان X و ي لنوع الزوج والعنصرين النائبين أ و ب لنوع الخريطة. أ و ب هي أنواع فائقة من X و ي ، لأن X و ي   يتم الإعلان عنها مع أ و ب كحدودهم العليا. (لاحظ أن معلمات نوع الطريقة العامة X و ي لا علاقة لها ب زوج الطبقة X و ي حدود.  الأسماء X و ي يتم إعادة استخدامه للطريقة العامة لتسهيل التعرف عليه كنوع معلم. باستخدام أربع معلمات من الخطور يمكننا أن نعلن عن التحميل الحقيقة الحقيقة الرقبة حسب: وهو نفس زيت نوف قطعة المكتب.

مثال

فئة SomeClass <T> {
  // مُهيئ ثابت، حقل ثابت، طريقة ثابتة
  ثابت {
    SomeClass< ت اختبار > = SomeClass< الجديد ت >(); // خطأ
  }
  خاص ثابت ت معلومات عالمية؛          // خطأ
  عام  ثابت ت الحصول على معلومات جلوبال () {        // خطأ
    إرجاع المعلومات العالمية؛
  }
  // مُهيئ غير ثابت، حقل غير ثابت، طريقة غير ثابتة
  { 
    SomeClass< ت اختبار > = SomeClass< الجديد ت >();
  }
  خاص        ت localInfo;
  عام         ت الحصول على معلومات محلية () { 
    إرجاع المعلومات المحلية؛
  }
  // أنواع متداخلة ثابتة
  عام ثابت فصل الفشل يمتد الاستثناء {
    نهائي خاص ت معلومات؛           // خطأ
    فشل عام( ت ر) { معلومات = ر؛ }      // خطأ
    عام ت getInfo() { معلومات الإرجاع؛ }    // خطأ
   }
  خاص واجهة قابل للنسخ {
    ت ينسخ()؛                       // خطأ
  }
  خاص التعداد ولاية {
    صالح، غير صالح؛
    خاص ت معلومات؛ // خطأ
    معلومات مجموعة الفراغ العام ( ت ر) { معلومات = ر؛ } // خطأ
    عام ت getInfo() { معلومات الإرجاع؛ }    // خطأ
  }
  // أنواع متداخلة غير ثابتة
  عام فصل ملحق {
    عام ت getInfo() { return localInfo; }
  }
}

يوضح المثال أنه لا يمكن توظيف معلم في السياق العام.  ويوضح أيضًا أن الواجهات المتداخلة وأنواع الرقم تعتبر أعضاء من النوع الثابت.  من الممكن فقط للفئات الداخلية، أي الفئات المتداخلة غير الثابتة، استخدام معلم الفئة للفئة العامة المضمنة.

نطاق معلم الوجه هو التعريف الكامل للوجه، مع استبعاد أي تداخل في الحقوق أو الأنواع.  وذلك لأن الحقوق والأنواع المتداخلة محددة في الواجهة لتكون متسقة مع بعضها البعض.

مثال

واجهة SomeInterface <T> {
  // مجال
  SomeClass< ت قيمة > = SomeClass< الجديدة ت >();  // خطأ
  // نوع متداخل
  فصل ملحق {
    عام ت الحصول على معلومات () {            // خطأ
      قيمة الإرجاع.getGlobalInfo();
    }
  }
  // طُرق
  ت getValue();
}

يوضح المثال أن حقول الواجهة ثابتة ضمنيًا، بحيث لا يمكن استخدام معلمة النوع في أي مكان في تعريف حقل الواجهة العامة.  وبالمثل، تعتبر الفئة المتداخلة فئة متداخلة ثابتة، وليست فئة داخلية، ولهذا السبب فإن استخدام معلمة النوع في أي مكان في الفئة المتداخلة غير قانوني.

الحل البديل للفئات والواجهات الثابتة المتداخلة:

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

مثال (الحل لهاحل الحلوى – عناء الحديث المتعدنة):

غلاف الطبقة <T> {
  نهائي خاص ت theObject;

  المجمع العام( ت t) { theObject = t; }
  عام ت getWrapper() { return theObject; }   عام غير قابل للتغيير <T> جعل غير قابل للتغيير () {
        إرجاع غير قابل للتغيير الجديد <T> (الكائن)؛
  }
  عام قابل للتغيير <T> ميكموتابل () {
        إرجاع متغير جديد <T> (الكائن)؛
  }
  خاص ثابت <A> A makeClone(A theObject) { ... }

  الطبقة النهائية العامة الثابتة غير قابلة للتغيير <A> { // هي فئة عامة الآن
        نهائي خاص أ theObject;

        عام غير قابل للتغيير( أ ارج) {
            theObject = makeClone(arg);
        }
        عام أ الحصول على ملف ملفوف () {
            إرجاع makeClone(theObject);
        }
  }
  فئة ثابتة عامة قابلة للتغيير <A> {
        ... مشابه ...
  }
}

لا يوجد مثل هذا الحل البديل لأنواع التعداد المتداخلة لأنها لا يمكن أن تكون عامة.

الحل البديل للفئات الثابتة المتداخلة:

إذا كان النوع الثابت المتداخل عبارة عن فئة، فإن الحل البديل هو تحويل الفئة الثابتة إلى فئة داخلية غير ثابتة.

مثال (الحل صحل – استخدم الطبقة الداخلية):

غلاف الطبقة <T> {
  نهائي خاص ت theObject;

  المجمع العام( ت t) { theObject = t; }
  عام ت getWrapper() { return theObject; }   عام قابل للتغيير makeMutable() {
      يعود هذا. جديد قابل للتغيير(theObject);
  }
  عام غير قابل للتغيير makeImmutable() {
      يعود هذا. جديد غير قابل للتغيير(theObject);
  }
  خاص ثابت <A> A makeClone(A theObject) { ... }

  الطبقة النهائية العامة غير قابلة للتغيير {  // لم تعد فئة ثابتة
      نهائي خاص ت theObject;

      عام غير قابل للتغيير( ت ارج) {
          theObject = makeClone(arg);
      }
      عام ت الحصول على ملف ملفوف () {
          إرجاع makeClone(theObject);
      }
  }
  الطبقة العامة قابلة للتغيير 
        ... مشابه ...
  }
}

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

مثال (تم تحسين الحل العربي):

غلاف الطبقة <T> {
  نهائي خاص ت theObject;

  المجمع العام( ت t) { theObject = t; }
  عام ت getWrapper() { return theObject; }   عام قابل للتغيير <T> ميكموتابل () {
      إرجاع this.new Mutable(theObject);
  }
  عام غير قابل للتغيير <T> جعل غير قابل للتغيير () {
      إرجاع this.new Immutable(theObject);
  }
  خاص ثابت <A> A makeClone(A theObject) { ... }

  واجهة عامة غير قابل للتغيير<S> {
      S getWrappedItem();
  }
  واجهة عامة قابل للتغيير<S> {
      S getWrappedItem();
      void setWrappedItem(S arg);
  }
  خاص التنفيذ غير القابل للتغيير للفئة النهائية تنفذ Immutable<T> { 

      النهائي الخاص T theObject؛

      عام ImmutableImplementation(T arg) {
          theObject = makeClone(arg);
      }
      public T getWrappedItem() {
          إرجاع makeClone(theObject);
      }
  }
  خاص تنفيذ فئة قابلة للتغيير تنفذ Mutable<T> { 
        ... مشابه ...
  }
}

كما ترون، يجب أن تكون الواجهات العامة المتداخلة عامة بينما الواجهات الداخلية الخاصة يمكن استخدامها من قبل معلم الواجهة الخاصة للواجهة المضمنة.

 

 

 

 

 

ترك الرد