Java sintaksisi biz yangi umumiy massiv yaratishimiz mumkinligini ko'rsatadi


Download 18.27 Kb.
Sana15.02.2023
Hajmi18.27 Kb.
#1201116
Bog'liq
tarmoq dasturlash mavzu No12


Mavzu: Umumiy ma’lumotlar tuzilmalarini (massivlar, ro‘yxatlar, daraxtlar va boshqalar) yaratish uchun sinf shablonlaridan foydalanish.

1.Kirish
Biz massivlardan generiklarni qo‘llab-quvvatlaydigan sinflar yoki funksiyalarning bir qismi sifatida foydalanishni xohlashimiz mumkin , ammo Java generiklarni boshqarish usuli tufayli bu qiyin bo‘lishi mumkin.


Ushbu qo'llanmada biz generiklarni massivlar bilan ishlatishdagi qiyinchiliklarni muhokama qilamiz. Keyin biz umumiy massivning namunasini yaratamiz.
Va nihoyat, Java API shunga o'xshash muammoni qanday hal qilganini ko'rib chiqamiz.
2. Umumiy massivlardan foydalanishda e'tiborga olish
Massivlar va generiklar o'rtasidagi muhim farq ularning turini tekshirishni qanday amalga oshirishidir. Xususan, massivlar ish vaqtida turdagi ma'lumotlarni saqlaydi va tekshiradi. Biroq, generiklar kompilyatsiya vaqtida turdagi xatolarni tekshiradi va ish vaqtida turdagi ma'lumotlarga ega emas.
Java sintaksisi biz yangi umumiy massiv yaratishimiz mumkinligini ko'rsatadi:
T[] elements = new T[size];
Ammo agar biz buni sinab ko'rsak, kompilyatsiya xatosiga duch kelamiz.
Buning sababini tushunish uchun keling, quyidagilarni ko'rib chiqaylik:
public T[] getArray(int size) {
T[] genericArray = new T[size]; // suppose this is allowed
return genericArray;
}
Bog'lanmagan umumiy T turi Ob'ektga echilganligi sababli , bizning ish vaqtidagi usulimiz quyidagicha bo'ladi:
public Object[] getArray(int size) {
Object[] genericArray = new Object[size];
return genericArray;
}Nusxalash
Agar biz usulimizni chaqirsak va natijani String massivida saqlasak:
String[] myArray = getArray(5);Nusxalash
Kod yaxshi kompilyatsiya qilinadi, lekin ClassCastException bilan ish vaqtida muvaffaqiyatsiz bo'ladi . Buning sababi, biz hozirgina Object[] ni String[] havolasiga tayinladik . Xususan, kompilyator tomonidan yashirin translatsiya Object[] ni bizning talab qilingan String[] turiga aylantira olmaydi .
Umumiy massivlarni to'g'ridan-to'g'ri ishga tushira olmasak ham, agar ma'lumotning aniq turi qo'ng'iroq kodi bilan ta'minlangan bo'lsa, ekvivalent operatsiyaga erishish mumkin.
3. Umumiy massivni yaratish
Misol uchun, sig'imi ma'lum bir o'lchamga o'rnatiladigan MyStack cheklangan stek ma'lumotlar strukturasini ko'rib chiqaylik. Biz stekning har qanday tur bilan ishlashini xohlayotganimiz sababli, oqilona amalga oshirish tanlovi umumiy massiv bo'ladi.
Birinchidan, biz E tipidagi umumiy massiv bo'lgan stekimiz elementlarini saqlash uchun maydon yaratamiz :
private E[] elements;Nusxalash
Keyin biz konstruktorni qo'shamiz:
public MyStack(Class clazz, int capacity) {
elements = (E[]) Array.newInstance(clazz, capacity);
}Nusxalash
Ikki parametr talab qiladigan umumiy massivimizni ishga tushirish uchun java.lang.reflect.Array#newInstance dan qanday foydalanishimizga e'tibor bering. Birinchi parametr yangi massiv ichidagi ob'ekt turini belgilaydi. Ikkinchi parametr massiv uchun qancha joy yaratish kerakligini belgilaydi. Array#newInstance ning natijasi Object tipidagi bo‘lgani uchun umumiy massivimizni yaratish uchun uni E[] ga o‘tkazishimiz kerak .
Bundan tashqari , Java-da ajratilgan so'z bo'lgan sinf emas , balki tip parametrlarini clazz deb nomlash konventsiyasiga e'tibor qaratishimiz kerak .
4. ArrayList ni ko'rib chiqish
4.1. Massiv o'rnida ArrayList dan foydalanish
Ko'pincha umumiy massiv o'rniga umumiy ArrayList dan foydalanish osonroq . Keling, MyStack-ni ArrayList- dan foydalanish uchun qanday o'zgartirishimiz mumkinligini ko'rib chiqaylik .
Birinchidan, biz elementlarimizni saqlash uchun maydon yaratamiz:
private List elements;Nusxalash
Keyin, stek konstruktorimizda biz ArrayList- ni boshlang'ich sig'im bilan ishga tushirishimiz mumkin:
elements = new ArrayList<>(capacity);Nusxalash
Bu bizning sinfimizni soddalashtiradi, chunki biz aks ettirishdan foydalanishimiz shart emas. Bundan tashqari, stekni yaratishda bizdan sinf literaliga o'tishimiz shart emas. ArrayList ning boshlang'ich sig'imini o'rnatishimiz mumkin bo'lsa , biz massiv bilan bir xil foyda olishimiz mumkin.
Shuning uchun, biz kamdan-kam hollarda yoki massivni talab qiladigan ba'zi tashqi kutubxonalar bilan bog'langanimizda generiklar massivlarini yaratishimiz kerak.
4.2. ArrayListni amalga oshirish
Qizig'i shundaki, ArrayListning o'zi umumiy massivlar yordamida amalga oshiriladi. Keling, qanday qilib ArrayList ichiga nazar tashlaylik.
Birinchidan, ro'yxat elementlari maydonini ko'rib chiqamiz:
transient Object[] elementData;
Eslatma ArrayList element turi sifatida Ob'ektdan foydalanadi . Bizning umumiy turimiz ish vaqtigacha noma'lum bo'lgani uchun Ob'ekt har qanday turdagi supersinf sifatida ishlatiladi.
Shuni ta'kidlash kerakki, ArrayList -dagi deyarli barcha amallar ushbu umumiy massivdan foydalanishi mumkin, chunki ular tashqi dunyoga qattiq terilgan massivni taqdim etishi shart emas (bir usuldan tashqari, toArray).
5. To‘plamdan massiv qurish
5.1. LinkedList misoli
Keling, Java Collections API-da umumiy massivlardan foydalanishni ko'rib chiqaylik, bu erda biz to'plamdan yangi massiv tuzamiz.
Birinchidan, biz String argumentli yangi LinkedList yaratamiz va unga elementlar qo'shamiz:
List items = new LinkedList();
items.add("first item");
items.add("second item");
Nusxalash
Keyin biz qo'shgan narsalar qatorini tuzamiz:
String[] itemsAsArray = items.toArray(new String[0]);Nusxalash
Bizning massivimizni yaratish uchun, List . toArray usuli kirish massivini talab qiladi. U ushbu massivdan faqat to'g'ri turdagi qaytish massivini yaratish uchun turdagi ma'lumotlarni olish uchun foydalanadi.
Yuqoridagi misolimizda biz yangi String[0] dan olingan qatorni yaratish uchun kirish massivi sifatida foydalandik .
5.2. LinkedList.toArray amalga oshirish
Keling, Java JDK da qanday amalga oshirilganligini ko'rish uchun LinkedList.toArray ichiga nazar tashlaylik.
Birinchidan, biz usul imzosini ko'rib chiqamiz:
public T[] toArray(T[] a)Nusxalash
Keyin kerak bo'lganda yangi massiv qanday yaratilishini ko'rib chiqamiz:
a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);Nusxalash
Oldingi stek misolimizdagi kabi yangi massivni yaratish uchun Array#newInstance dan qanday foydalanishiga e'tibor bering . Bundan tashqari, a parametri Array#newInstance turini taqdim etish uchun ishlatilishini ko'rishimiz mumkin . Nihoyat, umumiy massivni yaratish uchun Array#newInstance natijasi T[] ga uzatiladi .
6. Oqimlardan massivlar yaratish
Java Streams API bizga oqimdagi elementlardan massivlar yaratish imkonini beradi. To'g'ri turdagi massivni ishlab chiqarishimizga ishonch hosil qilish uchun bir nechta tuzoqlarga e'tibor berish kerak.
6.1. toArray dan foydalanish 
Biz elementlarni Java 8 Stream- dan massivga osongina o'zgartirishimiz mumkin:
Object[] strings = Stream.of("A", "AAA", "B", "AAB", "C")
.filter(string -> string.startsWith("A"))
.toArray();

assertThat(strings).containsExactly("A", "AAA", "AAB");


Nusxalash
Ammo shuni ta'kidlash kerakki, asosiy toArray funktsiyasi bizga String massivini emas, balki Object massivini taqdim etadi :
assertThat(strings).isNotInstanceOf(String[].class);Nusxalash
Yuqorida aytib o'tganimizdek, har bir massivning aniq turi boshqacha. Oqimdagi tur generik bo'lgani uchun kutubxonaning ish vaqtida turini aniqlashning imkoni yo'q .
6.2. Yozilgan massivni olish uchun toArray ortiqcha yukidan foydalanish
Umumiy yig'ish sinfi usullari ma'lum turdagi massivni yaratish uchun aks ettirishdan foydalansa, Java Streams kutubxonasi funktsional yondashuvdan foydalanadi. Stream uni toʻldirishga tayyor boʻlganda , toʻgʻri oʻlcham va turdagi massivni yaratadigan lambda yoki usul maʼlumotnomasida oʻtishimiz mumkin :
String[] strings = Stream.of("A", "AAA", "B", "AAB", "C")
.filter(string -> string.startsWith("A"))
.toArray(String[]::new);
assertThat(strings).containsExactly("A", "AAA", "AAB");
assertThat(strings).isInstanceOf(String[].class);Nusxalash
Biz o'tkazadigan usul IntFunction bo'lib , u butun sonni kirish sifatida qabul qiladi va shu o'lchamdagi yangi massivni qaytaradi. String[] konstruktori aynan shunday qiladi, shuning uchun biz String[]::new usulidan foydalanishimiz mumkin .
6.3. O'z turi parametri bilan generiklar
Tasavvur qilaylik, biz oqimimizdagi qiymatlarni o'zi turdagi parametrga ega bo'lgan ob'ektga aylantirmoqchimiz, masalan, List yoki Optional . Ehtimol, bizda qo'ng'iroq qilmoqchi bo'lgan API mavjud bo'lib, u Optional[] ni kiritish sifatida qabul qiladi.
Ushbu turdagi massivni e'lon qilish to'g'ri:
Optional[] strings = null;Nusxalash
Shuningdek, xarita usuli yordamida Stream ni osongina olishimiz va uni Stream> ga aylantirishimiz mumkin :
Stream> stream = Stream.of("A", "AAA", "B", "AAB", "C")
.filter(string -> string.startsWith("A"))
.map(Optional::of);Nusxalash
Biroq, agar biz massivni qurishga harakat qilsak, yana kompilyator xatosiga duch kelamiz:
// compiler error
Optional[] strings = new Optional[1];Nusxalash
Yaxshiyamki, bu misol bilan oldingi misollarimiz o'rtasida farq bor. String[] Object[] ning quyi sinfi bo'lmasa , Optional [] aslida Optional[] bilan bir xil ish vaqti turidir . Boshqacha qilib aytadigan bo'lsak, bu biz quyma turi orqali hal qilishimiz mumkin bo'lgan muammodir:
Stream> stream = Stream.of("A", "AAA", "B", "AAB", "C")
.filter(string -> string.startsWith("A"))
.map(Optional::of);
Optional[] strings = stream
.toArray(Optional[]::new);Nusxalash
Bu kod kompilyatsiya qiladi va ishlaydi, lekin bizga belgilanmagan topshiriq haqida ogohlantirish beradi. Buni tuzatish uchun usulimizga SuppressWarnings qo'shishimiz kerak :
@SuppressWarnings("unchecked")Nusxalash
6.4. Yordamchi funksiyadan foydalanish
Agar biz kodimizning bir nechta joylariga SuppressWarnings ni qo'shmaslikni istasak va umumiy massivning xom turdagi yaratilishini hujjatlashtirishni istasak, yordamchi funktsiyani yozishimiz mumkin:
@SuppressWarnings("unchecked")
static IntFunction genericArray(IntFunction arrayCreator) {
return size -> (R[]) arrayCreator.apply(size);
}Nusxalash
Ushbu funktsiya xom turdagi massivni bizga kerak bo'lgan aniq turdagi massivni yaratishni va'da qiladigan funktsiyaga aylantiradi:
Optional[] strings = Stream.of("A", "AAA", "B", "AAB", "C")
.filter(string -> string.startsWith("A"))
.map(Optional::of)
.toArray(genericArray(Optional[]::new));Nusxalash
Belgilanmagan topshiriq haqidagi ogohlantirishni bu erda bostirish shart emas.
Ammo shuni ta'kidlash kerakki, bu funktsiyani yuqori turlarga translyatsiya qilish uchun chaqirish mumkin. Misol uchun, agar bizning oqimimizda List tipidagi ob'ektlar bo'lsa , biz ArrayList massivini yaratish uchun genericArray-ni noto'g'ri chaqirishimiz mumkin :
ArrayList[] lists = Stream.of(singletonList("A"))
.toArray(genericArray(List[]::new));Nusxalash
Bu kompilyatsiya qilinadi, lekin ArrayList[] List[] ning pastki sinfi emasligi sababli ClassCastExceptionni chiqaradi . Kompilyator buning uchun tekshirilmagan topshiriq ogohlantirishini ishlab chiqaradi, shuning uchun uni aniqlash oson.

Download 18.27 Kb.

Do'stlaringiz bilan baham:




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling