JavaRush /Java Blog /Random-TL /Ano ang mga generic sa Java

Ano ang mga generic sa Java

Nai-publish sa grupo
Kamusta! Ngayon ay pag-uusapan natin ang tungkol sa generics. Dapat kong sabihin na marami kang matututunan na mga bagong bagay! Hindi lamang ito, kundi pati na rin ang mga susunod na lektura ay ilalaan sa generics. Ano ang mga generic sa Java - 1 Samakatuwid, kung ang paksang ito ay kawili-wili sa iyo, ikaw ay mapalad: ngayon ay marami kang matututunan tungkol sa mga tampok ng generics. Well, kung hindi, huminahon at magpahinga! :) Ito ay isang napakahalagang paksa at kailangan mong malaman ito. Magsimula tayo sa isang simpleng: “ano” at “bakit”. Ano ang generics? Ang mga generic ay mga uri na may parameter. Kapag gumagawa ng generic, tinukoy mo hindi lamang ang uri nito, kundi pati na rin ang uri ng data na dapat itong gumana. Sa tingin ko ang pinaka-halatang halimbawa ay pumasok na sa iyong isip - ito ay ArrayList! Narito kung paano namin ito karaniwang ginagawa sa programa:
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<String> myList1 = new ArrayList<>();
       myList1.add("Test String 1");
       myList1.add("Test String 2");
   }
}
Tulad ng maaari mong hulaan, ang kakaiba ng listahan ay hindi posibleng "ilagay" ang lahat dito: eksklusibo itong gumagana sa mga bagay String. Ngayon ay magsagawa tayo ng maikling iskursiyon sa kasaysayan ng Java at subukang sagutin ang tanong na: “bakit?” Para magawa ito, kami mismo ang magsusulat ng pinasimpleng bersyon ng klase ng ArrayList. Ang aming listahan ay maaari lamang magdagdag ng data sa panloob na hanay at matanggap ang data na ito:
public class MyListClass {

   private Object[] data;
   private int count;

   public MyListClass() {
       this.data = new Object[10];
       this.count = 0;
   }

   public void add(Object o) {
       this.data[count] = o;
       count++;
   }

   public Object[] getData() {
       return data;
   }
}
Sabihin nating gusto naming ang aming listahan ay mag-imbak lamang ng mga numero Integer. Wala kaming generics. Hindi namin tahasang tukuyin ang o instance ng check Integersa add(). Kung gayon ang aming buong klase ay magiging angkop lamang para sa Integer, at kakailanganin naming isulat ang parehong klase para sa lahat ng uri ng data na umiiral sa mundo! Nagpasya kaming umasa sa aming mga programmer at mag-iwan lamang ng komento sa code upang hindi sila magdagdag ng anumang hindi kailangan doon:
//use it ONLY with Integer data type
public void add(Object o) {
   this.data[count] = o;
   count++;
}
Hindi sinasadya ng isa sa mga programmer ang komentong ito at hindi sinasadyang sinubukang ilagay ang mga numero na may halong mga string sa listahan, at pagkatapos ay kalkulahin ang kanilang kabuuan:
public class Main {

   public static void main(String[] args) {

       MyListClass list = new MyListClass();
       list.add(100);
       list.add(200);
       list.add("Lolkek");
       list.add("Shalala");

       Integer sum1 = (Integer) list.getData()[0] + (Integer) list.getData()[1];
       System.out.println(sum1);

       Integer sum2 = (Integer) list.getData()[2] + (Integer) list.getData()[3];
       System.out.println(sum2);
   }
}
Output ng console: 300 Exception sa thread na "main" java.lang.ClassCastException: java.lang.String ay hindi maaaring i-cast sa java.lang.Integer sa Main.main(Main.java:14) Ano ang pinakamasama sa sitwasyong ito? Malayo sa pagiging kawalang-ingat ng isang programmer. Ang pinakamasama ay ang maling code ay napunta sa isang mahalagang lugar sa aming programa at matagumpay na naipon . Ngayon makikita natin ang error hindi sa yugto ng coding, ngunit sa yugto lamang ng pagsubok (at ito ang pinakamahusay na kaso!). Ang pag-aayos ng mga bug mamaya sa pag-unlad ay nagkakahalaga ng higit pa - parehong pera at oras. Ito ang tiyak na bentahe ng generics: ang isang generic na klase ay magbibigay-daan sa isang malas na programmer na makakita kaagad ng isang error. Ang code ay hindi lamang mag-compile!
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Integer> myList1 = new ArrayList<>();

       myList1.add(100);
       myList1.add(100);
       myList1.add("Lolkek");//error!
       myList1.add("Shalala");//error!
   }
}
Ang programmer ay agad na "mamulat" at agad na itama ang kanyang sarili. Sa pamamagitan ng paraan, hindi namin kailangang lumikha ng aming sariling klase Listupang makita ang ganitong uri ng error. Alisin lang ang uri ng mga bracket ( <Integer>) mula sa isang regular na ArrayList!
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

      List list = new ArrayList();

      list.add(100);
      list.add(200);
      list.add("Lolkek");
      list.add("Shalala");

       System.out.println((Integer) list.get(0) + (Integer) list.get(1));
       System.out.println((Integer) list.get(2) + (Integer) list.get(3));
   }
}
Output ng console: 300 Exception sa thread na "main" java.lang.ClassCastException: java.lang.String ay hindi maaaring i-cast sa java.lang.Integer sa Main.main(Main.java:16) Ibig sabihin, kahit na gamit ang "native" na mga tool Java, maaari mong gawin ang pagkakamaling ito at lumikha ng hindi ligtas na koleksyon. Gayunpaman, kung i-paste namin ang code na ito sa IDEa, makakakita kami ng babala: " Hindi naka-check na tawag para idagdag(E) bilang miyembro ng raw na uri ng java.util.List " Sinasabi nito sa amin na may maaaring magkamali kapag nagdaragdag ng elemento sa isang koleksyon na walang generics hindi sa ganitong paraan. Ngunit ano ang ibig sabihin ng pariralang "hilaw na uri"? Ang literal na pagsasalin ay magiging tumpak - “ raw type ” o “ dirty type ”. Raw typeay isang generic na klase kung saan inalis ang uri nito. Sa madaling salita, List myList1ito ay Raw type. Ang kabaligtaran raw typeay generic typeisang generic na klase (kilala rin bilang isang klase parameterized type), na ginawa nang tama, na may isang uri ng detalye. Halimbawa, List<String> myList1. Maaaring may tanong ka: bakit pinapayagan pa itong gamitin raw types? Simple lang ang dahilan. Ang mga tagalikha ng Java ay nag-iwan ng suporta sa wika raw typesupang hindi lumikha ng mga problema sa compatibility. Sa oras na inilabas ang Java 5.0 (lumalabas ang mga generic sa unang pagkakataon sa bersyong ito), marami nang code ang naisulat na gamit ang raw types. Samakatuwid, ang posibilidad na ito ay umiiral pa rin hanggang ngayon. Nabanggit na namin ang klasikong aklat ni Joshua Bloch na “Effective Java” nang higit sa isang beses sa mga lektura. Bilang isa sa mga lumikha ng wika, hindi niya pinansin ang paksa ng paggamit raw typesat sa aklat generic types. Ano ang mga generic sa Java - 2Ang Kabanata 23 ng aklat na ito ay may napakahusay na pamagat: "Huwag gumamit ng mga hilaw na uri sa bagong code." Ito ay isang bagay na kailangan mong tandaan. Kapag gumagamit ng mga generic na klase, huwag kailanman generic typegawing raw type.

Mga Na-type na Paraan

Pinapayagan ka ng Java na mag-type ng mga indibidwal na pamamaraan, na lumilikha ng tinatawag na mga generic na pamamaraan. Bakit maginhawa ang gayong mga pamamaraan? Una sa lahat, dahil pinapayagan ka nitong magtrabaho sa iba't ibang uri ng mga parameter. Kung ang parehong lohika ay maaaring ligtas na mailapat sa iba't ibang uri, ang isang generic na pamamaraan ay isang mahusay na solusyon. Tingnan natin ang isang halimbawa. Sabihin nating mayroon kaming ilang uri ng listahan myList1. Nais naming alisin ang lahat ng mga halaga mula dito, at punan ang lahat ng mga libreng puwang ng isang bagong halaga. Ito ang magiging hitsura ng aming klase na may generic na pamamaraan:
public class TestClass {

   public static <T> void fill(List<T> list, T val) {
       for (int i = 0; i < list.size(); i++)
           list.set(i, val);
   }

   public static void main(String[] args) {

       List<String> strings = new ArrayList<>();
       strings.add("Старая строка 1");
       strings.add("Старая строка 2");
       strings.add("Старая строка 3");

       fill(strings, "Новая строка");

       System.out.println(strings);

       List<Integer> numbers = new ArrayList<>();
       numbers.add(1);
       numbers.add(2);
       numbers.add(3);

       fill(numbers, 888);
       System.out.println(numbers);
   }
}
Bigyang-pansin ang syntax, mukhang hindi karaniwan:
public static <T> void fill(List<T> list, T val)
Ang uri ng pagbabalik ay pinangungunahan ng <T>, na nagsasaad ng generic na paraan. Sa kasong ito, ang pamamaraan ay tumatagal ng 2 parameter bilang input: isang listahan ng mga bagay na T at isa pang hiwalay na bagay na T. Sa pamamagitan ng paggamit ng <T>, ang pag-type ng pamamaraan ay nakakamit: hindi kami makakapasa ng isang listahan ng mga string at isang numero doon. Isang listahan ng mga string at isang string, isang listahan ng mga numero at isang numero, isang listahan ng aming mga bagay Catat isa pang bagay Cat- iyon ang tanging paraan. Ang pamamaraan ay main()malinaw na nagpapakita na ang pamamaraan ay fill()madaling gumagana sa iba't ibang uri ng data. Una, kinakailangan bilang input ang isang listahan ng mga string at isang string, at pagkatapos ay isang listahan ng mga numero at isang numero. Output ng console: [Newline, Newline, Newline] [888, 888, 888] Isipin kung fill()kailangan namin ng method logic para sa 30 iba't ibang klase, at wala kaming mga generic na pamamaraan. Mapipilitan kaming isulat ang parehong paraan ng 30 beses, para lang sa iba't ibang uri ng data! Ngunit salamat sa mga generic na pamamaraan, maaari naming muling gamitin ang aming code! :)

Mga uri ng klase

Hindi mo lamang magagamit ang mga generic na klase na ibinigay sa Java, ngunit lumikha din ng iyong sarili! Narito ang isang simpleng halimbawa:
public class Box<T> {

   private T t;

   public void set(T t) {
       this.t = t;
   }

   public T get() {
       return t;
   }

   public static void main(String[] args) {

       Box<String> stringBox = new Box<>();

       stringBox.set("Старая строка");
       System.out.println(stringBox.get());
       stringBox.set("Новая строка");

       System.out.println(stringBox.get());

       stringBox.set(12345);//ошибка компиляции!
   }
}
Ang aming klase Box<T>("kahon") ay nai-type. Ang pagkakaroon ng pagtatalaga ng isang uri ng data ( ) dito sa panahon ng paglikha <T>, hindi na namin magagawang maglagay ng mga bagay ng iba pang mga uri dito. Ito ay makikita sa halimbawa. Kapag lumilikha, tinukoy namin na ang aming object ay gagana sa mga string:
Box<String> stringBox = new Box<>();
At kapag sa huling linya ng code sinubukan naming ilagay ang numero 12345 sa loob ng kahon, nakakakuha kami ng error sa compilation! Kaya lang, gumawa kami ng sarili naming generic na klase! :) Dito na nagtatapos ang lecture namin ngayon. Ngunit hindi kami nagpapaalam sa mga generics! Sa susunod na mga lektura, pag-uusapan natin ang tungkol sa mas advanced na mga tampok, kaya huwag magpaalam! ) Good luck sa iyong pag-aaral! :)
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION