java - لماذا لا ينبغي أن يكون التعداد الحرفي لجافا جافا قادراً على الحصول على معلمات النوع العام؟




generics enums (5)

Bec Becue "enum" هو اختصار للتعداد. إنها مجرد مجموعة من الثوابت المسماة التي تقف بدلاً من الأرقام الترتيبية لجعل الشفرة قابلة للقراءة بشكل أفضل.

لا أرى ما يمكن أن يكون المعنى المقصود لثابت نوع معلمات.

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

public enum MyEnum<T> {
    LITERAL1<String>,
    LITERAL2<Integer>,
    LITERAL3<Object>;
}

يمكن أن تكون معلمة النوع العامة هذه <T> مفيدة في أماكن مختلفة. تخيل معلمة نوع عامة لطريقة:

public <T> T getValue(MyEnum<T> param);

أو حتى في صف التعداد نفسه:

public T convert(Object o);

أكثر مثال ملموس # 1

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

  • التعداد ، لأنه يمكنني بعد ذلك تعداد مجموعة محدودة من مفاتيح الخاصية
  • علم الوراثة ، لأنه يمكن أن يكون عندئذ أمان نوع على مستوى الأسلوب لتخزين الخصائص
public interface MyProperties {
     public <T> void put(MyEnum<T> key, T value);
     public <T> T get(MyEnum<T> key);
}

أكثر مثال ملموس # 2

لدي تعداد لأنواع البيانات:

public interface DataType<T> {}

public enum SQLDataType<T> implements DataType<T> {
    TINYINT<Byte>,
    SMALLINT<Short>,
    INT<Integer>,
    BIGINT<Long>,
    CLOB<String>,
    VARCHAR<String>,
    ...
}

من الواضح أن كل تعداد حرفي له خصائص إضافية تعتمد على النوع العام <T> ، في حين أنه في الوقت نفسه ، يكون تعدادًا (غير قابل للتغيير ، مفرد ، يمكن عده ، إلخ.)

سؤال:

لم يفكر أحد في هذا؟ هل هذا القيد متعلق مترجم؟ وبالنظر إلى حقيقة أن الكلمة " التعداد " تُنفَّذ كسكر نحوي ، تمثل رمزًا تم إنشاؤه إلى JVM ، لا أفهم هذا القيد.

من يستطيع أن يشرح لي هذا؟ قبل الإجابة ، ضع في اعتبارك ما يلي:

  • وأنا أعلم يتم محو أنواع عامة :-)
  • أعلم أن هناك حلولًا تستخدم كائنات الفئة. انهم الحلول.
  • تؤدي الأنواع العامة إلى ظهور قوالب من نوع المترجم حيثما كان ذلك ساريًا (على سبيل المثال عند استدعاء الطريقة convert ()
  • النوع العام <T> سيكون على التعداد. ومن ثم فهي ملزمة بكل من معاني التعداد. ومن ثم سيعرف المجمع ، أي نوع سيتم تطبيقه عند كتابة شيء مثل String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject); String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);
  • وينطبق الشيء نفسه على معلمة النوع العامة في طريقة T getvalue() . يمكن أن يقوم المحول البرمجي بتطبيق نوع الكتابة عند استدعاء String string = someClass.getValue(LITERAL1)

أظن أنه في الأساس لا يمكن أن يحرض التعداد

أين ستقوم بتعيين فئة T ، إذا سمحت لك JVM بذلك؟

التعداد هو البيانات التي من المفترض أن تكون هي نفسها دائمًا ، أو على الأقل أنها لن تتغير ديناميكيًا.

جديد MyEnum <> ()؟

لا يزال النهج التالي قد يكون مفيدا

public enum MyEnum{

    LITERAL1("s"),
    LITERAL2("a"),
    LITERAL3(2);

    private Object o;

    private MyEnum(Object o) {
        this.o = o;
    }

    public Object getO() {
        return o;
    }

    public void setO(Object o) {
        this.o = o;
    }   
}

بصراحة هذا يبدو وكأنه أكثر من حل بحثا عن مشكلة من أي شيء آخر.

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

خذ مثالاً على التعداد الكتابي. هذه ليست مفيدة أو متسقة للغاية:

public enum Planet<T>{
    Earth<Planet>,
    Venus<String>,
    Mars<Long>
    ...etc.
}

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

بالإضافة إلى كيف يمكنك إدارة التحويلات المعقدة؟

على سبيل المثال

public enum BadIdea<T>{
   INSTANCE1<Long>,
   INSTANCE2<MyComplexClass>;
}

من السهل بما فيه الكفاية مع Integer لتزويد اسم أو ترتيبي. لكن الأدوية الجنسية تسمح لك بتوفير أي نوع. كيف يمكنك إدارة التحويل إلى MyComplexClass ؟ أنت الآن تتستر على تركيبتين من خلال إجبار المترجم على معرفة أن هناك مجموعة فرعية محدودة من الأنواع التي يمكن توفيرها للتعدادات العامة وإدخال مزيد من الارتباك على المفهوم (Generics) الذي يبدو بالفعل مستعصيا على الكثير من المبرمجين.


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

تحديث: تتم إضافته حاليًا إلى اللغة تحت JEP 301: التوعية المحسّنة .


يتم الآن مناقشة هذا الأمر اعتبارًا من JEP-301 Enums المحسّن . المثال المعطى في JEP هو ، بالضبط ما كنت أبحث عنه:

enum Argument<X> { // declares generic enum
   STRING<String>(String.class), 
   INTEGER<Integer>(Integer.class), ... ;

   Class<X> clazz;

   Argument(Class<X> clazz) { this.clazz = clazz; }

   Class<X> getClazz() { return clazz; }
}

Class<String> cs = Argument.STRING.getClazz(); //uses sharper typing of enum constant




enums