java - فوت - معنى كلمة عنوان بالانجليزي




ما هو النوع الخام ولماذا لا نستخدمه؟ (10)

ما هي الأنواع الأولية في Java ، ولماذا أسمع في كثير من الأحيان أنه لا ينبغي استخدامها في الكود الجديد؟

الأنواع الخام هي التاريخ القديم للغة جافا. في البداية كانت هناك Collections Objects لا شيء أكثر ولا أقل. كل عملية على Collections مطلوبة يلقي من Object إلى النوع المطلوب.

List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);

في حين أن هذا العمل في معظم الأوقات ، حدثت أخطاء

List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here

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

List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine

للمقارنة:

// Old style collections now known as raw types
List aList = new ArrayList(); //Could contain anything
// New style collections with Generics
List<String> aList = new ArrayList<String>(); //Contains only Strings

أكثر تعقيدا واجهة المقارنة:

//raw, not type save can compare with Other classes
class MyCompareAble implements CompareAble
{
   int id;
   public int compareTo(Object other)
   {return this.id - ((MyCompareAble)other).id;}
}
//Generic
class MyCompareAble implements CompareAble<MyCompareAble>
{
   int id;
   public int compareTo(MyCompareAble other)
   {return this.id - other.id;}
}

لاحظ أنه من المستحيل تنفيذ واجهة CompareAble باستخدام compareTo(MyCompareAble) مع أنواع خام. لماذا يجب عدم استخدامها:

  • يجب وضع أي Object مخزّن في Collection قبل أن يمكن استخدامه
  • يمكّن استخدام الأدوية الوقائية من التحقق من الوقت
  • استخدام أنواع الخام هو نفسه تخزين كل قيمة Object

ما يفعله المحول البرمجي: Generics متوافق مع الإصدارات السابقة ، ويستخدم نفس فئات Java كما تفعل أنواع الخام. السحر يحدث في الغالب في وقت الترجمة.

List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);

سيتم تجميعها على النحو التالي:

List someStrings = new ArrayList();
someStrings.add("one"); 
String one = (String)someStrings.get(0);

هذا هو نفس الرمز الذي تكتبه إذا استخدمت الأنواع الأولية مباشرةً. أعتقد أنني لست متأكداً مما يحدث مع واجهة CompareAble ، أعتقد أنه يخلق وظيفتين MyCompareAble ، أحدهما يأخذ MyCompareAble والآخر يأخذ Object MyCompareAble إلى الأول بعد MyCompareAble .

ما هي البدائل لأنواع الخام: استخدام generics

الأسئلة:

  • ما هي الأنواع الأولية في Java ، ولماذا أسمع في كثير من الأحيان أنه لا ينبغي استخدامها في الكود الجديد؟
  • ما هو البديل إذا لم نتمكن من استخدام أنواع خام ، وكيف هو أفضل؟

ما هو نوع الخام؟

تحدد مواصفات لغة Java نوعًا خامًا كما يلي:

JLS 4.8 أنواع خام

يتم تعريف النوع الخام ليكون واحدا من:

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

  • نوع مصفوفة نوع عنصرها هو نوع خام.

  • نوع عضو غير static من نوع raw R غير موروث من superclass أو superinterface من R

إليك مثال لتوضيح:

public class MyType<E> {
    class Inner { }
    static class Nested { }

    public static void main(String[] args) {
        MyType mt;          // warning: MyType is a raw type
        MyType.Inner inn;   // warning: MyType.Inner is a raw type

        MyType.Nested nest; // no warning: not parameterized type
        MyType<Object> mt1; // no warning: type parameter given
        MyType<?> mt2;      // no warning: type parameter given (wildcard OK!)
    }
}

هنا ، MyType<E> هو نوع من المعلمات ( JLS 4.5 ). من الشائع أن يشير هذا العام إلى هذا النوع ببساطة MyType ، لكن الاسم MyType<E> تقنيًا.

mt له نوع خام (وينتج تحذيراً تجميعياً) بواسطة النقطة الأولى في التعريف أعلاه ؛ inn لديه أيضا نوع الخام من النقطة الثالثة.

MyType.Nested ليس نوع معلمات ، على الرغم من أنه نوع عضو لنوع معلمات MyType<E> ، لأنه static .

mt1 و mt2 بمعلمات النوع الفعلية ، لذا فهي ليست أنواعًا خامًا.

ما هو خاص جدا حول أنواع الخام؟

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

List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!

تعمل التعليمة البرمجية الموجودة أعلاه بشكل جيد ، ولكن لنفترض أيضًا أن لديك ما يلي:

for (Object o : names) {
    String name = (String) o;
    System.out.println(name);
} // throws ClassCastException!
  //    java.lang.Boolean cannot be cast to java.lang.String

نواجه الآن مشكلة في وقت التشغيل ، لأن names تحتوي على شيء لا يمثل instanceof String .

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

List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!

وبالطبع ، إذا كنت تريد أن تسمح names بوجود Boolean ، فيمكنك حينئذٍ الإعلان عنها List<Object> names ، وستتم ترجمة التعليمة البرمجية المذكورة أعلاه.

أنظر أيضا

كيف يختلف نوع خام عن استخدام <Object> كمعلمات الكتابة؟

ما يلي هو اقتباس من الإصدار الثاني من Java الفعال ، البند 23: لا تستخدم الأنواع الأولية في الكود الجديد :

فقط ما هو الفرق بين القائمة نوع الخام ونوع المعلمة List<Object> ؟ وبصورة غير متقنة ، اختار الفريق الأول التحقق من النوع العام ، في حين أخبر هذا الأخير المترجم صراحة أنه قادر على احتجاز الأشياء من أي نوع. بينما يمكنك تمرير List<String> إلى معلمة من نوع List ، لا يمكنك تمريرها إلى معلمة من نوع List<Object> . توجد قواعد فرعية لأصول بديلة ، List<String> هي نوع فرعي من List النوع List ، ولكنها ليست من النوع list بالأنواع List<Object> . ونتيجة لذلك ، تفقد نوع الأمان إذا كنت تستخدم نوع خام مثل List ، ولكن ليس إذا كنت تستخدم نوعًا معلَّقًا مثل List<Object> .

لتوضيح هذه النقطة ، ضع في اعتبارك الطريقة التالية التي تأخذ List<Object> وتلحق new Object() .

void appendNewObject(List<Object> list) {
   list.add(new Object());
}

Generics في Java غير ثابتة. List<String> ليست List<Object> ، لذلك سوف يؤدي التالي إلى إنشاء تحذير مترجم:

List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!

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

أنظر أيضا

كيف يختلف نوع خام عن استخدام <?> كمعلمة نوع؟

List<Object> ، List<String> ، وما هي كلها List<?> ، لذلك قد يكون من المغري مجرد القول أنها مجرد List بدلا من ذلك. ومع ذلك ، يوجد فرق كبير: نظرًا لأن List<E> تحدد فقط add(E) ، فلا يمكنك إضافة أي كائن عشوائي إلى List<?> . من ناحية أخرى ، بما أن List النوع الأولي لا تحتوي على أمان اكتب ، يمكنك add أي شيء إلى List .

جرِّب الشكل التالي من المقتطف السابق:

static void appendNewObject(List<?> list) {
    list.add(new Object()); // compilation error!
}
//...

List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!

قام المترجم بعمل رائع لحمايتك من احتمال خرق نوع الثبات في List<?> ! List<?> ! إذا كنت قد أعلنت المعلمة List list النوع الأولية ، فسيتم تجميع الشفرة ، وستنتهك طبقة ثابتة من List<String> names .

النوع الخام هو محو ذلك النوع

العودة إلى JLS 4.8:

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

[...]

الطبقة الفائقة (على التوالي ، الفائقة) للنوع الخام هي محو الطبقة الفائقة (superinterface) لأي من بارامترات النوع العام.

إن نوع المنشئ أو طريقة المثيل أو الحقل غير static لنوع خام C غير الموروث من الطبقة الفائقة أو السطوح الفائقة هو النوع الخام الذي يتوافق مع محو نوعه في التعريف العام المقابل لـ C

وبعبارة أبسط ، عند استخدام نوع خام ، يتم أيضًا محو التركيبات وطرق المثال والحقول غير static .

خذ المثال التالي:

class MyType<E> {
    List<String> getNames() {
        return Arrays.asList("John", "Mary");
    }

    public static void main(String[] args) {
        MyType rawType = new MyType();
        // unchecked warning!
        // required: List<String> found: List
        List<String> names = rawType.getNames();
        // compilation error!
        // incompatible types: Object cannot be converted to String
        for (String str : rawType.getNames())
            System.out.print(str);
    }
}

عندما نستخدم MyType الخام ، يتم مسح getNames أيضًا ، بحيث تقوم بإرجاع List raw!

يستمر JLS 4.6 في توضيح ما يلي:

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

يخضع أيضًا نوع إرجاع طريقة ومعلمات النوع لطريقة أو مُنشئ عام لإحباط إذا تم مسح الطريقة أو توقيع المنشئ.

لا يحتوي محو توقيع طريقة عامة على معلمات من النوع.

يحتوي تقرير الأخطاء التالي على بعض الأفكار من Maurizio Cimadamore ، وهو أحد مطوري البرامج ، و Alex Buckley ، أحد مؤلفي JLS ، حول سبب حدوث هذا النوع من السلوك: https://bugs.openjdk.java.net/browse/JDK-6400189 . (باختصار ، فإنه يجعل المواصفات أبسط).

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

هنا اقتبس آخر من JLS 4.8:

يُسمح باستخدام الأنواع الأولية فقط كتنازل لتوافق الشفرة القديمة. لا يشجع بشدة استخدام أنواع الخام في التعليمات البرمجية المكتوبة بعد إدخال genericity في لغة برمجة Java. من الممكن أن الإصدارات المستقبلية من لغة برمجة Java لن تسمح باستخدام الأنواع الأولية.

يحتوي Java 2nd Edition الفعال أيضًا على ما يلي:

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

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

باختصار ، يجب عدم استخدام أنواع الخام في الكود الجديد. يجب عليك دائما استخدام أنواع معلمات .

لا توجد استثناءات؟

لسوء الحظ ، نظرًا لأن أدوات Java البرمجية غير قابلة للتعديل ، هناك استثناءان حيث يجب استخدام أنواع المواد الخام في الشفرة الجديدة:

  • القيم الحرفية للفئة ، على سبيل المثال List.class ، وليس List<String>.class
  • instanceof operand ، على سبيل المثال o instanceof Set ، وليس o instanceof Set<String>

أنظر أيضا


النوع الأولي هو اسم فئة أو واجهة عامة بدون أي وسيطات كتابة. على سبيل المثال ، نظرًا لفئة Box العامة:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

لإنشاء نوع معلمات من Box<T> ، يمكنك توفير وسيطة نوع فعلية لمعلمة النوع الرسمي T :

Box<Integer> intBox = new Box<>();

إذا تم حذف وسيطة النوع الفعلية ، فيمكنك إنشاء نوع خام من Box<T> :

Box rawBox = new Box();

لذلك ، Box هو النوع الأساسي من النوع العام Box<T> . ومع ذلك ، لا يعد نوع فئة أو واجهة عامة غير نوع خام.

تظهر أنواع Raw في التعليمة البرمجية القديمة لأن الكثير من فئات API (مثل فئات المجموعات) لم تكن عامة قبل JDK 5.0. عند استخدام أنواع خام ، فأنت تحصل بشكل أساسي على سلوك ما قبل الأدوية - حيث يمنحك Box Object . للتوافق مع الإصدارات السابقة ، يُسمح بتعيين نوع معلمات لنوعه الخام:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;               // OK

ولكن إذا قمت بتعيين نوع خام إلى نوع معلَّل ، فستتلقى تحذيرًا:

Box rawBox = new Box();           // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox;     // warning: unchecked conversion

ستحصل أيضًا على تحذير إذا كنت تستخدم نوعًا خامًا لاستدعاء طرق عامة محددة في النوع العام المطابق:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8);  // warning: unchecked invocation to set(T)

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

يحتوي قسم Ereure Type على مزيد من المعلومات حول كيفية استخدام برنامج التحويل البرمجي Java للأنواع الأولية.

رسائل خطأ لم يتم التحقق منها

كما ذكرنا سابقًا ، عند خلط الشفرة القديمة مع الرمز العام ، قد تصادف رسائل تحذير مشابهة لما يلي:

ملاحظة: يستخدم Example.java عمليات غير محددة أو غير آمنة.

ملاحظة: Recompile مع -Xlint: غير محددة للتفاصيل.

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

public class WarningDemo {
    public static void main(String[] args){
        Box<Integer> bi;
        bi = createBox();
    }

    static Box createBox(){
        return new Box();
    }
}

المصطلح "غير محدد" يعني أن المترجم لا يحتوي على معلومات نوع كافية لإجراء جميع عمليات التحقق اللازمة لضمان سلامة النوع. يتم تعطيل التحذير "غير محدد" بشكل افتراضي ، على الرغم من أن المحول البرمجي يعطي تلميحا. لمشاهدة جميع التحذيرات "غير المحددة" ، أعد ترجمة -Xlint: غير محددة.

إعادة إنشاء المثال السابق باستخدام -Xlint: غير محدد ، يكشف عن المعلومات الإضافية التالية:

WarningDemo.java:4: warning: [unchecked] unchecked conversion
found   : Box
required: Box<java.lang.Integer>
        bi = createBox();
                      ^
1 warning

لتعطيل التحذيرات غير المحددة تمامًا ، استخدم علامة -Xlint: -conhecked. التعليق التوضيحي @SuppressWarnings("unchecked") يمنع تحذيرات غير محددة. إذا لم تكن معتادًا على صيغة @SuppressWarnings ، فراجع التعليقات التوضيحية.

المصدر الأصلي: Java Tutorials


النوع الأولي هو عدم وجود معلمة نوع عند استخدام نوع عام.

لا يجب استخدام النوع الخام لأنه قد يتسبب في حدوث أخطاء في وقت التشغيل ، مثل إدخال double في ما كان من المفترض أن يكون Set من int s.

Set set = new HashSet();
set.add(3.45); //ok

عند استعادة الأشياء من Set ، لا تعرف ما هو الخروج. لنفترض أنك تتوقع أن تكون كلها int s ، فإنك تقوم بإدخالها إلى Integer ؛ استثناء في وقت التشغيل عندما يأتي 3.45 double على طول.

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

Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.

لقد عثرت على هذه الصفحة بعد إجراء بعض التمارين النموذجية ولديها نفس الغموض.

============== لقد ذهبت من هذا الرمز كما قدمته العينة ===============

public static void main(String[] args) throws IOException {

    Map wordMap = new HashMap();
    if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            countWord(wordMap, args[i]);
        }
    } else {
        getWordFrequency(System.in, wordMap);
    }
    for (Iterator i = wordMap.entrySet().iterator(); i.hasNext();) {
        Map.Entry entry = (Map.Entry) i.next();
        System.out.println(entry.getKey() + " :\t" + entry.getValue());
    }

====================== إلى هذا الرمز ========================

public static void main(String[] args) throws IOException {
    // replace with TreeMap to get them sorted by name
    Map<String, Integer> wordMap = new HashMap<String, Integer>();
    if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            countWord(wordMap, args[i]);
        }
    } else {
        getWordFrequency(System.in, wordMap);
    }
    for (Iterator<Entry<String, Integer>> i = wordMap.entrySet().iterator(); i.hasNext();) {
        Entry<String, Integer> entry =   i.next();
        System.out.println(entry.getKey() + " :\t" + entry.getValue());
    }

}

================================================== =============================

قد يكون أكثر أمانًا ولكن استغرق 4 ساعات لتحييد الفلسفة ...


ما يقال هو أن list هي List كائنات غير محددة. هذا هو أن جافا لا تعرف أي نوع من الكائنات داخل القائمة. ثم عندما ترغب في تكرار القائمة ، يجب عليك إدخال كل عنصر ، حتى تتمكن من الوصول إلى خصائص هذا العنصر (في هذه الحالة ، السلسلة).

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

private static List<String> list = new ArrayList<String>();

وهنا حالة أخرى حيث سوف يعض أنواع الخام لك:

public class StrangeClass<T> {
  @SuppressWarnings("unchecked")
  public <X> X getSomethingElse() {
    return (X)"Testing something else!";
  }

  public static void main(String[] args) {
    final StrangeClass<Object> withGeneric    = new StrangeClass<>();
    final StrangeClass         withoutGeneric = new StrangeClass();
    final String               value1,
                               value2;

    // Works
    value1 = withGeneric.getSomethingElse();

    // Produces compile error:
    // incompatible types: java.lang.Object cannot be converted to java.lang.String
    value2 = withoutGeneric.getSomethingElse();
  }
}

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


يريدك المترجم كتابة هذا:

private static List<String> list = new ArrayList<String>();

لأنه بخلاف ذلك ، يمكنك إضافة أي نوع تريده إلى list ، مما يجعل إنشاء مثيل new ArrayList<String>() لا معنى له. إن Java generics هي ميزة وقت تجميع فقط ، لذلك فإن الكائن الذي تم إنشاؤه باستخدام new ArrayList<String>() سيقبل بسعادة عناصر Integer أو JFrame إذا تم تعيينه إلى مرجع لقائمة "raw type" - الكائن نفسه لا يعرف شيئًا عن الأنواع من المفترض أن يحتوي ، فقط المترجم.


ما هو النوع الخام ولماذا غالباً ما أسمع أنه لا ينبغي استخدامهم في الكود الجديد؟

"النوع الأولي" هو استخدام فئة عامة دون تحديد وسيطة (أنواع) النوع لنوع (أو قيم) المعلمات ، على سبيل المثال استخدام List بدلاً من List<String> . عندما تم إدخال الأدوية البديلة إلى Java ، تم تحديث عدة فئات لاستخدام الأدوية. استخدام هذه الفئة كـ "نوع raw" (بدون تحديد وسيطة نوع) يسمح بتعليمة البرمجية القديمة ليتم تجميعها.

يتم استخدام "أنواع Raw" للتوافق مع الإصدارات السابقة. لا ينصح باستخدامها في الكود الجديد لأن استخدام الفئة العامة مع وسيطة النوع يسمح بكتابة أقوى ، مما قد يحسن بدوره فهم الشفرة ويؤدي إلى اكتشاف المشاكل المحتملة في وقت سابق.

ما هو البديل إذا لم نتمكن من استخدام أنواع خام ، وكيف هو أفضل؟

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

على سبيل المثال ، بالنسبة إلى طريقة يرغب المبرمج في التأكد من أن متغير القائمة المسمى 'names' يحتوي على السلاسل فقط:

List<String> names = new ArrayList<String>();
names.add("John");          // OK
names.add(new Integer(1));  // compile error

 private static List<String> list = new ArrayList<String>();

يجب عليك تحديد معلمة النوع.

ينصح التحذير بأن الأنواع التي يتم تعريفها لدعم generics يجب أن تكون معلمة ، بدلاً من استخدام شكلها الخام.

يتم تعريف القائمة لدعم الأدوية: public class List<E> . يتيح هذا العديد من العمليات الآمنة من النوع ، والتي يتم فحصها وقت التجميع.





raw-types