JavaRush /Java блогы /Random-KK /Java тіліндегі генериктер дегеніміз не

Java тіліндегі генериктер дегеніміз не

Топта жарияланған
Сәлеметсіз бе! Бүгін біз генериктер туралы сөйлесетін боламыз. Айта кету керек, сіз көптеген жаңа нәрселерді үйренесіз! Бұл ғана емес, келесі бірнеше дәрістер де генериктер туралы болмақ. Java тіліндегі генериктер дегеніміз не - 1 Сондықтан, егер бұл тақырып сізді қызықтырса, сіз бақыттысыз: бүгін сіз генериктердің ерекшеліктері туралы көп нәрсені білесіз. Егер жоқ болса, тынышталып, демалыңыз! :) Бұл өте маңызды тақырып және оны білу керек. Қарапайымнан бастайық: «не» және «неге». Генерик деген не? Генериктер - параметрі бар түрлер. Жалпы құру кезінде оның түрін ғана емес, сонымен бірге ол жұмыс істеуі керек деректер түрін де көрсетесіз. Менің ойымша, ең айқын мысал сіздің ойыңызға келді - бұл ArrayList! Біз оны әдетте бағдарламада қалай жасаймыз:
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");
   }
}
Сіз болжағандай, тізімнің ерекшелігі - оған бәрін «толтыру» мүмкін емес: ол тек нысандармен жұмыс істейді String. Енді Java тарихына қысқаша экскурсия жасап, «неге?» деген сұраққа жауап беруге тырысайық. Ол үшін біз ArrayList класының жеңілдетілген нұсқасын жазамыз. Біздің тізім тек ішкі массивке деректерді қосып, осы деректерді ала алады:
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;
   }
}
Біздің тізім тек сандарды сақтауын қалаймыз делік Integer. Бізде генериктер жоқ. IntegerБіз тексерудің o данасын нақты көрсете алмаймыз add(). Сонда біздің бүкіл класс тек үшін жарамды болады Integerжәне біз әлемде бар барлық деректер түрлері үшін бірдей класс жазуымыз керек! Біз бағдарламашыларымызға сенуді шешеміз және олар қажетсіз ештеңе қоспауы үшін codeқа түсініктеме қалдырамыз:
//use it ONLY with Integer data type
public void add(Object o) {
   this.data[count] = o;
   count++;
}
Бағдарламашылардың бірі бұл түсініктемені жіберіп алды және байқаусызда тізімге жолдармен аралас сандарды енгізуге тырысты, содан кейін олардың сомасын есептейді:
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);
   }
}
Консоль шығысы: 300 "main" ағынындағы ерекше жағдай java.lang.ClassCastException: java.lang.String Main.main(Main.java:14) мекенжайында java.lang.Integer файлына көшіру мүмкін емес. Бұл жағдайдағы ең жаманы қандай? Бағдарламашының зейінсіздігінен алыс. Ең сорақысы, қате code біздің бағдарламада маңызды орынға түсіп, сәтті құрастырылды . Енді біз қатені codeтау кезеңінде емес, тек тестілеу кезеңінде көреміз (және бұл ең жақсы жағдайда!). Кейінірек әзірлеу кезінде қателерді түзету әлдеқайда қымбатқа түседі - ақша да, уақыт та. Бұл генериктердің артықшылығы: жалпы класс бақытсыз бағдарламашыға қатені дереу анықтауға мүмкіндік береді. Код жай ғана құрастырылмайды!
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!
   }
}
Бағдарламашы бірден «өзіне келіп», өзін бірден түзетеді. Айтпақшы, Listмұндай қатені көру үшін өз класымызды құрудың қажеті жоқ еді. Жай ғана типті жақшаларды ( <Integer>) қарапайым 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));
   }
}
Консоль шығысы: 300 "негізгі" ағындағы ерекше жағдай java.lang.ClassCastException: java.lang.String Main.main(Main.java:16) мекенжайында java.lang.Integer файлына трансляциялау мүмкін емес Java, сіз бұл қатені жасай аласыз және қауіпті топтама жасай аласыз. Однако, если вставить этот code в IDEa, мы увидим предупреждение: “ Unchecked call to add(E) as a member of raw type of java.util.List ” Нам подсказывают, что при добавлении element в коллекцию без дженериков что-то может пойти Олай емес. Бірақ «шикі түрі» деген тіркес нені білдіреді? Сөзбе-сөз аударма өте дәл болады – “ шикі түрі ” немесе “ лас түрі ”. Raw typeоның түрі жойылған жалпы класс болып табылады. Басқаша айтқанда, List myList1бұл Raw type. Қарама-қарсы raw type- типтік спецификациямен дұрыс жасалған generic typeжалпы класс (сонымен қатар класс деп аталады ). parameterized typeМысалы, List<String> myList1. Сізде сұрақ туындауы мүмкін: неге оны пайдалануға рұқсат етілген raw types? Себебі қарапайым. raw typesJava жасаушылар үйлесімділік мәселелерін тудырмау үшін тілде қолдау қалдырды . Java 5.0 шығарылған кезде (генериктер осы нұсқада бірінші рет пайда болды), көптеген codeтар қазірдің өзінде көмегімен жазылған raw types. Сондықтан бұл мүмкіндік бүгінгі күні де бар. Джошуа Блохтың «Тиімді Java» классикалық кітабын біз дәрістерде бірнеше рет айтқан болатынбыз. Тіл жасаушылардың бірі ретінде ол кітапта қолдану raw typesжәне қолдану тақырыбын да назардан тыс қалдырған емес generic types. Java тіліндегі генериктер дегеніміз не - 2Бұл кітаптың 23-тарауында өте көрнекті тақырып бар: «Жаңа codeта өңделмеген түрлерді пайдаланбаңыз.» Бұл есте сақтау керек нәрсе. Жалпы сыныптарды пайдаланған кезде оларды ешқашан generic typeтүрлендірмеңіз raw type.

Терілген әдістер

Java жалпы әдістер деп аталатындарды жасай отырып, жеке әдістерді теруге мүмкіндік береді. Неліктен мұндай әдістер ыңғайлы? Ең алдымен, олар әртүрлі типтегі параметрлермен жұмыс істеуге мүмкіндік беретіндіктен. Егер бірдей логиканы әртүрлі түрлерге қауіпсіз қолдануға болатын болса, жалпы әдіс тамаша шешім болып табылады. Мысал қарастырайық. Бізде қандай да бір тізім бар делік myList1. Біз одан барлық мәндерді алып тастағымыз келеді және барлық бос орындарды жаңа мәнмен толтырғымыз келеді. Жалпы әдіспен біздің сынып келесідей болады:
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);
   }
}
Синтаксиске назар аударыңыз, ол сәл ерекше көрінеді:
public static <T> void fill(List<T> list, T val)
Қайтару түрінің алдында жалпы әдісті көрсететін <T> болады. Бұл жағдайда әдіс кіріс ретінде 2 параметрді қабылдайды: T нысандарының тізімі және басқа жеке нысан T. <T> пайдалану арқылы әдісті теруге қол жеткізіледі: біз жолдар тізімі мен санды ол жерге жібере алмаймыз. Жолдар мен жолдар тізімі, сандар мен сандар тізімі, біздің нысандардың тізімі Catжәне басқа нысан Cat- бұл жалғыз жол. Бұл әдіс әртүрлі деректер түрлерімен оңай жұмыс істейтінін main()анық көрсетеді . fill()Біріншіден, ол кіріс ретінде жолдар мен жолдар тізімін, содан кейін сандар мен сандардың тізімін алады. Консоль шығысы: [Newline, Newline, Newline] [888, 888, 888] Елестетіп көріңізші, fill()бізге 30 түрлі сыныптар үшін әдіс логикасы қажет болды және бізде жалпы әдістер жоқ. Біз әртүрлі деректер түрлері үшін бір әдісті 30 рет жазуға мәжбүр болар едік! Бірақ жалпы әдістердің арқасында біз codeты қайта пайдалана аламыз! :)

Терілген сыныптар

Сіз тек Java-да берілген жалпы сыныптарды пайдаланып қана қоймай, өзіңізді де жасай аласыз! Міне, қарапайым мысал:
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);//ошибка компиляции!
   }
}
Біздің сынып Box<T>(«қорап») теріледі. Жасау кезінде оған деректер түрін ( ) тағайындаған соң <T>, біз оған басқа түрдегі нысандарды орналастыра алмаймыз. Мұны мысалдан көруге болады. Жасау кезінде біздің нысан жолдармен жұмыс істейтінін көрсеттік:
Box<String> stringBox = new Box<>();
Ал codeтың соңғы жолында 12345 санын қораптың ішіне қоюға тырысқанда, компиляция қатесін аламыз! Дәл осылай, біз өзіміздің жалпы классымызды жасадық! :) Осымен бүгінгі лекциямыз аяқталды. Бірақ біз генериктермен қоштаспаймыз! Келесі дәрістерде біз қосымша мүмкіндіктер туралы айтатын боламыз, сондықтан қоштаспаңыз! ) Оқуыңа сәттілік! :)
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION