JavaRush /مدونة جافا /Random-AR /استخدام varargs عند العمل مع الأدوية الجنيسة

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

نشرت في المجموعة
مرحبًا! في درس اليوم سنواصل دراسة الأدوية الجنيسة. لقد حدث أن هذا موضوع كبير، ولكن لا يوجد مكان تذهب إليه - وهذا جزء مهم للغاية من اللغة :) عندما تدرس وثائق Oracle حول الأدوية العامة أو تقرأ الأدلة على الإنترنت، سوف تصادف المصطلحات الأنواع غير القابلة للإصلاح والأنواع القابلة للإصلاح . ما هو نوع الكلمة "Reifiable"؟ حتى لو كان كل شيء جيدًا في اللغة الإنجليزية، فمن غير المرجح أن تتمكن من تحقيق ذلك. دعونا نحاول الترجمة! استخدام varargs عند العمل مع الأدوية العامة - 2
*شكرًا جوجل، لقد ساعدتني كثيرًا -_-*
النوع القابل لإعادة البناء هو النوع الذي تكون معلوماته متاحة بالكامل في وقت التشغيل. في لغة جافا، تتضمن هذه الأنواع الأنواع الأولية والأنواع غير العامة. في المقابل، الأنواع غير القابلة للإصلاح هي أنواع يتم مسح معلوماتها وجعلها غير متاحة في وقت التشغيل. هذه مجرد معلومات عامة - List<String> و List<Integer> وما إلى ذلك.

بالمناسبة، هل تتذكر ما هو الفارارج ؟

في حالة نسيانك، فهذه وسيطات متغيرة الطول. إنها مفيدة في المواقف التي لا نعرف فيها بالضبط عدد الوسائط التي يمكن تمريرها إلى طريقتنا. على سبيل المثال، إذا كان لدينا فئة آلة حاسبة ولها طريقة sum. sum()يمكنك تمرير رقمين، 3، 5، أو أي عدد تريده إلى الطريقة . سيكون من الغريب جدًا تحميل الطريقة بشكل زائد في كل مرة sum()لمراعاة جميع الخيارات الممكنة. بدلا من ذلك يمكننا القيام بذلك:
public class SimpleCalculator {

   public static int sum(int...numbers) {

       int result = 0;

       for(int i : numbers) {

           result += i;
       }

       return result;
   }

   public static void main(String[] args) {

       System.out.println(sum(1,2,3,4,5));
       System.out.println(sum(2,9));
   }
}
إخراج وحدة التحكم:

15
11
لذا، فإن الاستخدام varargsمع الأدوية الجنيسة له بعض الميزات المهمة. دعونا نلقي نظرة على هذا الرمز:
import javafx.util.Pair;
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static <E> void addAll(List<E> list, E... array) {

       for (E element : array) {
           list.add(element);
       }
   }

   public static void main(String[] args) {
       addAll(new ArrayList<String>(),  //  здесь все нормально
               "Leonardo da Vinci",
               "Vasco de Gama"
       );

       // а здесь мы получаем предупреждение
       addAll(new ArrayList<Pair<String, String>>(),
               new Pair<String, String>("Leonardo", "da Vinci"),
               new Pair<String, String>("Vasco", "de Gama")
       );
   }
}
تأخذ الطريقة قائمة وأي عدد من الكائنات addAll()كمدخلات ، ثم تضيف كل هذه الكائنات إلى القائمة. في الطريقة نسمي طريقتنا مرتين . في المرة الأولى نضيف سطرين عاديين. كل شيء على ما يرام هنا. في المرة الثانية نضيف كائنين . وهنا نحصل فجأة على تحذير: List<E>Emain()addAll()ListListPair<String, String>

Unchecked generics array creation for varargs parameter
ماذا يعني ذلك؟ لماذا نتلقى إنذارًا وما علاقته به array؟ Array- هذه مصفوفة، ولا توجد مصفوفات في الكود الخاص بنا! لنبدأ بالثانية. يذكر التحذير مصفوفة لأن المترجم يحول الوسائط ذات الطول المتغير (varargs) إلى مصفوفة. بمعنى آخر، توقيع طريقتنا هو addAll():
public static <E> void addAll(List<E> list, E... array)
في الواقع يبدو مثل هذا:
public static <E> void addAll(List<E> list, E[] array)
أي أنه في الطريقة main()، سيقوم المترجم بتحويل الكود الخاص بنا إلى هذا:
public static void main(String[] args) {
   addAll(new ArrayList<String>(),
      new String[] {
        "Leonardo da Vinci",
        "Vasco de Gama"
      }
   );
   addAll(new ArrayList<Pair<String,String>>(),
        new Pair<String,String>[] {
            new Pair<String,String>("Leonardo","da Vinci"),
            new Pair<String,String>("Vasco","de Gama")
        }
   );
}
كل شيء على ما يرام مع المصفوفة String. ولكن مع مجموعة Pair<String, String>- لا. الحقيقة هي أن Pair<String, String>هذا نوع غير قابل للإصلاح. أثناء التجميع، سيتم مسح كافة المعلومات حول أنواع المعلمات (<String, String>). غير مسموح بإنشاء صفائف من النوع غير القابل للReifiable في Java . يمكنك التحقق من ذلك إذا حاولت إنشاء زوج مصفوفة يدويًا<String, String>
public static void main(String[] args) {

   //  ошибка компиляции! Generic array creation
  Pair<String, String>[] array = new Pair<String, String>[10];
}
السبب واضح - نوع السلامة. كما تتذكر، عند إنشاء مصفوفة، يجب عليك الإشارة إلى الكائنات (أو الأوليات) التي ستخزنها هذه المصفوفة.
int array[] = new int[10];
في أحد الدروس السابقة، قمنا بفحص آلية مسح الكتابة بالتفصيل. لذلك، في هذه الحالة، نتيجة لمحو الأنواع، فقدنا المعلومات التي Pairتم تخزينها في كائناتنا <String, String>. سيكون إنشاء مصفوفة غير آمن. عند استخدام الأساليب ذات الأدوية varargsوالأدوية العامة، تأكد من تذكر محو الكتابة وكيفية عمله بالضبط. إذا كنت واثقًا تمامًا من الكود الذي كتبته، وتعلم أنه لن يسبب أي مشاكل، فيمكنك تعطيل varargsالتحذيرات المرتبطة به باستخدام تعليق توضيحي@SafeVarargs
@SafeVarargs
public static <E> void addAll(List<E> list, E... array) {

   for (E element : array) {
       list.add(element);
   }
}
إذا قمت بإضافة هذا التعليق التوضيحي إلى طريقتك، فلن يظهر التحذير الذي واجهناه سابقًا. هناك مشكلة أخرى محتملة عند استخدام varargsالأدوية الجنيسة معًا وهي التلوث بالأكوام. استخدام varargs عند العمل مع الأدوية العامة - 4يمكن أن يحدث التلوث في الحالات التالية:
import java.util.ArrayList;
import java.util.List;

public class Main {

   static List<String> makeHeapPollution() {
       List numbers = new ArrayList<Number>();
       numbers.add(1);
       List<String> strings = numbers;
       strings.add("");
       return strings;
   }

   public static void main(String[] args) {

       List<String> stringsWithHeapPollution = makeHeapPollution();

       System.out.println(stringsWithHeapPollution.get(0));
   }
}
إخراج وحدة التحكم:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
بعبارات بسيطة، تلوث الكومة هو الموقف الذي يجب أن تكون فيه الكائنات من النوع 1 في الكومة А، ولكن ينتهي الأمر بالكائنات من النوع هناك B، بسبب أخطاء تتعلق بسلامة الكتابة. في مثالنا هذا ما يحدث. قمنا أولاً بإنشاء متغير خام numbersوتخصيصه لمجموعة عامة ArrayList<Number>. وبعد ذلك أضفنا الرقم هناك 1.
List<String> strings = numbers;
في هذا السطر، حاول المترجم تحذيرنا من الأخطاء المحتملة من خلال إصدار التحذير " مهمة لم يتم التحقق منها... "، لكننا تجاهلناها. ونتيجة لذلك، لدينا متغير عام من النوع List<String>يشير إلى مجموعة عامة من النوع ArrayList<Number>. من الواضح أن هذا الوضع يمكن أن يؤدي إلى مشكلة! هذا ما يحصل. باستخدام المتغير الجديد، نضيف سلسلة إلى المجموعة. كانت الكومة ملوثة - أضفنا أولاً رقمًا ثم سلسلة إلى المجموعة المكتوبة. لقد حذرنا المترجم، لكننا تجاهلنا تحذيره، ولم نتلقى النتائج ClassCastExceptionإلا أثناء تشغيل البرنامج. ما علاقة الأمر بالأمر varargs؟ الاستخدام varargsمع الأدوية الجنيسة يمكن أن يؤدي بسهولة إلى تلوث الكومة. إليك مثال بسيط:
import java.util.Arrays;
import java.util.List;

public class Main {

   static void makeHeapPollution(List<String>... stringsLists) {
       Object[] array = stringsLists;
       List<Integer> numbersList = Arrays.asList(66,22,44,12);

       array[0] = numbersList;
       String str = stringsLists[0].get(0);
   }

   public static void main(String[] args) {

       List<String> cars1 = Arrays.asList("Ford", "Fiat", "Kia");
       List<String> cars2 = Arrays.asList("Ferrari", "Bugatti", "Zaporozhets");

       makeHeapPollution(cars1, cars2);
   }
}
ما الذي يحدث هنا؟ نظرًا لمحو الكتابة، فإن أوراق المعلمات الخاصة بنا (سنسميها "أوراق" بدلاً من "قوائم" للراحة) هي -
List<String>...stringsLists
- سيتحول إلى مصفوفة من الأوراق - List[]بنوع غير معروف (لا تنس أن varargs يتحول إلى مصفوفة عادية نتيجة للتجميع). ولهذا السبب، يمكننا بسهولة تعيين متغير Object[] arrayفي السطر الأول من الطريقة - لقد تم مسح الأنواع من أوراقنا! والآن لدينا متغير من النوع Object[]، حيث يمكننا إضافة أي شيء على الإطلاق - جميع الكائنات في Java ترث من Object! الآن ليس لدينا سوى مجموعة من أوراق السلسلة. لكن بفضل استخدام varargsالأنواع ومحوها، يمكننا بسهولة إضافة ورقة أرقام إليها، وهو ما نقوم به. نتيجة لذلك، نقوم بتلويث الكومة عن طريق خلط كائنات من أنواع مختلفة. ستكون النتيجة هي نفس الاستثناء ClassCastExceptionعند محاولة قراءة سلسلة من المصفوفة. إخراج وحدة التحكم:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
هذه هي العواقب غير المتوقعة التي يمكن أن تنجم عن استخدام آلية تبدو بسيطة varargs:) وبهذا تنتهي محاضرتنا اليوم. لا تنس حل بعض المشكلات، وإذا كان لديك الوقت والطاقة، فادرس الأدبيات الإضافية. " جافا الفعالة " لن تقرأ نفسها! :) أرك لاحقًا!
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION