JavaRush /Java blogi /Random-UZ /Jeneriklar bilan ishlashda vararglardan foydalanish

Jeneriklar bilan ishlashda vararglardan foydalanish

Guruhda nashr etilgan
Salom! Bugungi darsda biz generiklarni o'rganishni davom ettiramiz. Shunday bo'ladiki, bu katta mavzu, lekin boradigan joy yo'q - bu tilning juda muhim qismidir :) Jeneriklar bo'yicha Oracle hujjatlarini o'rganayotganingizda yoki Internetda qo'llanmalarni o'qiyotganingizda, siz atamalarni uchratasiz. Qayta tiklanmaydigan turlar va qayta tiklanadigan turlar . "Qayta tiklanadigan" so'z qanday? Ingliz tilida hamma narsa yaxshi bo'lsa ham, siz uni uchratishingiz dargumon. Keling, tarjima qilishga harakat qilaylik! Jeneriklar bilan ishlashda vararglardan foydalanish - 2
*rahmat Google, siz ko'p yordam berdingiz -_-*
Qayta tiklanadigan tip - bu ish vaqtida ma'lumotlari to'liq mavjud bo'lgan tur. Java tilida bular ibtidoiy, xom-tiplar va umumiy bo'lmagan turlarni o'z ichiga oladi. Bundan farqli o'laroq, qayta tiklanmaydigan turlar ma'lumotlari o'chiriladigan va ish vaqtida mavjud bo'lmagan turlardir. Bular faqat umumiydir - List<String> , List<Integer> va boshqalar.

Aytgancha, vararglar nima ekanligini eslaysizmi ?

Agar siz unutgan bo'lsangiz, bu o'zgaruvchan uzunlikdagi argumentlardir. Ular bizning usulimizga qancha argumentlar berilishi mumkinligini aniq bilmaydigan vaziyatlarda yordam beradi. Misol uchun, agar bizda kalkulyator sinfi bo'lsa va unda usul mavjud bo'lsa sum. Usulga sum()2 ta raqamni, 3, 5 yoki xohlaganingizcha berishingiz mumkin . sum()Barcha mumkin bo'lgan variantlarni hisobga olish uchun har safar usulni ortiqcha yuklash juda g'alati bo'lar edi . Buning o'rniga biz buni qila olamiz:
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));
   }
}
Konsol chiqishi:

15
11
varargsShunday qilib, generiklar bilan birgalikda foydalanish ba'zi muhim xususiyatlarga ega. Keling, ushbu kodni ko'rib chiqaylik:
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")
       );
   }
}
Usul addAll()kirish sifatida ro'yxat List<E>va istalgan miqdordagi ob'ektlarni oladi Eva keyin ushbu ob'ektlarning barchasini ro'yxatga qo'shadi. Usulda main()biz usulimizni ikki marta chaqiramiz addAll(). Birinchi marta ikkita oddiy qatorni qo'shamiz List. Bu yerda hammasi yaxshi. ListIkkinchi marta biz ikkita ob'ektni qo'shamiz Pair<String, String>. Va bu erda biz to'satdan ogohlantirish olamiz:

Unchecked generics array creation for varargs parameter
Bu nima degani? Nima uchun biz ogohlantirish olamiz va bu bilan qanday aloqasi bor array? Array- bu massiv va bizning kodimizda hech qanday massiv yo'q! Keling, ikkinchisidan boshlaylik. Ogohlantirish massiv haqida gapiradi, chunki kompilyator o'zgaruvchan uzunlikdagi argumentlarni (varargs) massivga aylantiradi. Boshqacha qilib aytganda, bizning usulimizning imzosi addAll():
public static <E> void addAll(List<E> list, E... array)
Bu aslida shunday ko'rinadi:
public static <E> void addAll(List<E> list, E[] array)
Ya'ni usulida main()kompilyator bizning kodimizni shunga o'zgartiradi:
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")
        }
   );
}
Massiv bilan hamma narsa yaxshi String. Ammo massiv bilan Pair<String, String>- yo'q. Gap shundaki, Pair<String, String>bu qayta tiklanmaydigan tur. Kompilyatsiya paytida parametr turlari (<String, String>) haqidagi barcha ma'lumotlar o'chib ketadi. Java-da qayta tiklanmaydigan turdagi massivlarni yaratishga ruxsat berilmaydi . Agar siz Pair<String, String> massivini qo'lda yaratishga harakat qilsangiz, buni tekshirishingiz mumkin
public static void main(String[] args) {

   //  ошибка компиляции! Generic array creation
  Pair<String, String>[] array = new Pair<String, String>[10];
}
Sababi aniq - xavfsizlik turi. Esingizda bo'lsa, massiv yaratishda ushbu massiv qaysi ob'ektlarni (yoki ibtidoiylarni) saqlashini ko'rsatishingiz kerak.
int array[] = new int[10];
Oldingi darslardan birida biz turni o'chirish mexanizmini batafsil ko'rib chiqdik. Shunday qilib, bu holda, turlarni o'chirish natijasida biz Pairjuftliklar ob'ektlarimizda saqlangan ma'lumotni yo'qotdik <String, String>. Massiv yaratish xavfli bo'ladi. Umumiy va umumiy usullardan foydalanganda varargs, turni o'chirish va uning qanday ishlashi haqida unutmang. Agar siz yozgan kodingizga mutlaqo ishonchingiz komil bo'lsa va u hech qanday muammo tug'dirmasligini bilsangiz, varargsizoh yordamida u bilan bog'liq ogohlantirishlarni o'chirib qo'yishingiz mumkin.@SafeVarargs
@SafeVarargs
public static <E> void addAll(List<E> list, E... array) {

   for (E element : array) {
       list.add(element);
   }
}
Agar siz ushbu izohni usulingizga qo'shsangiz, biz ilgari duch kelgan ogohlantirish ko'rinmaydi. Jeneriklarni birgalikda ishlatishda yuzaga kelishi mumkin bo'lgan yana bir muammo varargs- bu to'pning ifloslanishi. Jeneriklar bilan ishlashda vararglardan foydalanish - 4Kontaminatsiya quyidagi holatlarda sodir bo'lishi mumkin:
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));
   }
}
Konsol chiqishi:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Oddiy so'z bilan aytganda, yig'ma ifloslanish - bu 1-turdagi ob'ektlar uyada bo'lishi kerak bo'lgan holat А, ammo turdagi ob'ektlar Bxavfsizlik xatosi tufayli u erda tugaydi. Bizning misolimizda shunday bo'ladi. Avval biz Raw o'zgaruvchisini yaratdik numbersva uni umumiy to'plamga tayinladik ArrayList<Number>. Shundan so'ng biz u erda raqamni qo'shdik 1.
List<String> strings = numbers;
Ushbu qatorda kompilyator bizni " Tekshirilmagan topshiriq... " ogohlantirishini berib, yuzaga kelishi mumkin bo'lgan xatolar haqida ogohlantirishga harakat qildi, ammo biz bunga e'tibor bermadik. Natijada, bizda List<String>turning umumiy to'plamiga ishora qiluvchi umumiy o'zgaruvchi mavjud ArrayList<Number>. Bu holat aniq muammoga olib kelishi mumkin! Bu sodir bo'ladi. Yangi o'zgaruvchimizdan foydalanib, biz to'plamga satr qo'shamiz. Uyum ifloslangan - biz terilgan to'plamga avval raqamni, keyin esa qatorni qo'shdik. Kompilyator bizni ogohlantirdi, lekin biz uning ogohlantirishiga e'tibor bermadik, natijani ClassCastExceptionfaqat dastur ishlayotgan paytda oldik. Bunga nima aloqasi bor varargs? Jeneriklar bilan foydalanish varargsosongina to'plangan ifloslanishga olib kelishi mumkin. Mana oddiy misol:
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);
   }
}
Bu yerda nima bo'lyapti? Turni o'chirish tufayli, bizning parametr varaqlarimiz (qulaylik uchun ularni "ro'yxatlar" o'rniga "varaqlar" deb ataymiz) -
List<String>...stringsLists
- varaqlar massiviga aylanadi - List[]noma'lum turdagi (kompilyatsiya natijasida vararglar muntazam massivga aylanishini unutmang). Shu sababli, biz usulning birinchi qatorida osongina o'zgaruvchiga topshiriq berishimiz mumkin Object[] array- turlari bizning varaqlarimizdan o'chirildi! Va endi bizda har qanday narsani qo'shishimiz mumkin bo'lgan turdagi o'zgaruvchilar bor Object[]- Java'dagi barcha ob'ektlar meros qilib olinadi Object! Hozir bizda faqat qator varaqlar mavjud. Ammo turlardan foydalanish varargsva o'chirish tufayli biz ularga raqamlar varag'ini osongina qo'shishimiz mumkin, biz buni qilamiz. Natijada, biz har xil turdagi narsalarni aralashtirib, uyumni ifloslantiramiz. ClassCastExceptionNatija qatordan satrni o'qishga urinayotganda bir xil istisno bo'ladi . Konsol chiqishi:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Bu oddiy ko'rinadigan mexanizmdan foydalanish natijasida yuzaga kelishi mumkin bo'lgan kutilmagan oqibatlar varargs:) Va bugungi ma'ruzamiz shu bilan tugaydi. Bir nechta muammolarni hal qilishni unutmang, agar vaqt va kuchingiz qolsa, qo'shimcha adabiyotlarni o'rganing. " Effektiv Java " o'zini o'zi o'qimaydi! :) Ko'rishguncha!
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION