سؤال

إذا أعلنت فئة كحقل:

Class fooClass;

Eclipse يعطيني التحذير:

الفصل هو نوع خام. يجب أن تكون المراجع إلى فئة النوع العام محددة

ماذا يعني هذا في الممارسة العملية؟ ولماذا حثت على القيام بذلك؟ إذا طلبت Eclipse عن "حل سريع" ، فإنه يعطيني:

Class<?> fooClass;

الذي لا يبدو أنه يضيف قيمة كبيرة ولكن لم يعد يحذر.

تحرير: لماذا الطبقة عامة؟ هل يمكن أن تعطي مثالا على المعلمة ، أي يمكن أن يكون هناك استخدام صحيح لشيء آخر غير <?> ?

تحرير: واو! لم أدرك أعماق هذا. لقد شاهدت أيضًا لعبة Java Buzzler وهي بالتأكيد خائفة من مصائد الدب. لذلك سأستخدم دائمًا

Class<MyString> myStringClass = MyString.class;

عوضا عن

Class myStringClass = MyString.class;

(لكن بعد أن استخدمت Java من اليوم الأول ، لم ألاحظ حقًا عندما أصبح الفصل عامًا) ؛

ملاحظة: لقد قبلت oxbow_lakes لأن هذا أمر منطقي بالنسبة لي ، لكنه من الواضح أنه منطقة معقدة للغاية. أود أن أحث جميع المبرمجين على استخدام المحددة Class<MyString> عوضا عن Class. و Class<?> أكثر أمانًا من Class.

هل كانت مفيدة؟

المحلول

الأنواع الخام والبطاقات البرية غير المحدودة

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

السبب هو أن نوع خام, ، بمعنى آخر Class, ، يمنع المترجم من إجراء عمليات فحص من النوع العام. هذا هو ، إذا كنت تستخدم الأنواع الأولية ، أنت تخريب نظام النوع. فمثلا:

public void foo(Class<String> c) { System.out.println(c); }

يمكن أن يطلق عليه بالتالي (سوف يتجمع كلاهما و يجري):

Class r = Integer.class
foo(r); //THIS IS OK (BUT SHOULDN'T BE)

ولكن ليس بواسطة:

Class<?> w = Integer.class
foo(w); //WILL NOT COMPILE (RIGHTLY SO!)

من خلال استخدام نموذج غير RAW دائمًا ، حتى عندما يجب استخدامك ? نظرًا لأنه لا يمكنك معرفة ماهية المعلمة النوع (أو تحدها) ، فإنك تسمح للمترجم بالسبب في صحة برنامجك بشكل كامل مما لو كنت تستخدم أنواعًا أولية.


لماذا الأنواع الخام على الإطلاق؟

ال مواصفات لغة جافا يقول:

يُسمح باستخدام الأنواع الأولية فقط كامتياز لتوافق الكود القديم

يجب عليك دائمًا تجنبها. البطاقة البرية غير المحدودة ? ربما يكون من الأفضل وصفه في مكان آخر ولكن يعني بشكل أساسي "هذا هو معلمة على نوع ما ، لكنني لا أعرف (أو رعاية) ما هو عليه". هذا ليس هو نفسه الأنواع الخام, ، والتي هي رجس ولا توجد بلغات أخرى مع الأدوية ، مثل سكالا.


لماذا يتم تحديد الفئة؟

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

public interface FooService

وأريد حقن تنفيذها ، باستخدام خاصية النظام لتحديد الفصل المراد استخدامه.

Class<?> c = Class.forName(System.getProperty("foo.service"));

لا أعرف في هذه المرحلة أن صفي ، هو الصحيح يكتب:

//next line throws ClassCastException if c is not of a compatible type
Class<? extends FooService> f = c.asSubclass(FooService.class); 

الآن يمكنني إنشاء مثيل FooService:

FooService s = f.newInstance(); //no cast

نصائح أخرى

الذي لا يبدو أنه يضيف قيمة كبيرة ولكن لم يعد يحذر.

أنت على حق. لكن هذا قد يضيف قيمة:

Class<FooClass> fooClass;

أو ، إذا كان أكثر ملاءمة:

Class<? extends FooClass> fooClass;

أو

Class<FooInterface> fooClass;

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

لأنه ، منذ JDK 5 ، Class لديه الآن نوع المعلمة ، مما يجعل Class كائن عام. هذا ضروري (نظرًا لأن إدخال الأدوية الجيرية) للمترجم للقيام بفحص النوع (في وقت الترجمة ، بالطبع).

Class<?> يعني "فئة غير معروفة" حيث ? هو الأدوية الجيلية البرية. يعني ذلك fooClass من النوع Class<?> يقبل أ Class الذي يطابق نوع أي شيء.

مثال نموذجي:

Class<?> classUnknown = null;
classUnknown = ArrayList.class; //This compiles.

يمكنك ، على نحو فعال ، أن يكون نوعًا محددًا ليكون أكثر تحديداً ، على سبيل المثال:

Class<ArrayList> = ArrayList.class;

ملاحظة نضع في اعتبارنا أن Class<List> listClass = ArrayList.class; لن يتم تجميع (على الرغم من أن ArrayList هو قائمة) ولكن (كما ذكر مارك بيترز في التعليق) Class<? extends List> listClass = ArrayList.class; لا يجمع (بفضل Wildcard).

جافادوك من فصل يعطي الفصل بعض الأفكار حول سبب وجود معلمات الكتابة لهذا الفئة:

T - نوع الفئة التي تم تصميمها بواسطة هذا Class هدف. على سبيل المثال ، نوع String.class هو Class<String>.يستخدم Class<?> إذا كان الفصل الدراسي غير معروف.

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

    public T newInstance() 
        throws InstantiationException, IllegalAccessException
    {
    if (System.getSecurityManager() != null) {
        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader());
    }
    return newInstance0();
    }

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

النظر في المثال في السؤال ، إذا تم الإعلان عن مثيل الفصل بدلاً من ذلك:

Class<String> fooClass;
Class<Integer> barClass;
String aString;

بعد ذلك ، من المستحيل الحصول على الكود التالي لتجميعه:

aString = barClass.newInstance();

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

لأن استخدام الأنواع الأولية بدلاً من الأنواع المعلمة لها العديد من المزالق.

أحدها هو أنه في حالة استخدام نوع خام ، يتم فقد جميع الأدوية الجنيسة في الفصل. حتى تلك المحددة لكل ميثود.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top