JavaRush /Блоги Java /Random-TG /Генерикҳо барои гурбаҳо
Viacheslav
Сатҳи

Генерикҳо барои гурбаҳо

Дар гурӯҳ нашр шудааст
Генерикҳо барои гурбаҳо - 1

Муқаддима

Имрӯз рӯзи олӣ барои ёдоварӣ кардани он чизест, ки мо дар бораи Java медонем. Тибқи ҳуҷҷати муҳимтарин, яъне. Мушаххасоти забони Java (JLS - Java Specifiaction Language Language), Java забони сахт чопшуда аст, тавре ки дар боби " Боби 4. Намудҳо, арзишҳо ва тағирёбандаҳо " тавсиф шудааст. Ин чӣ маъно дорад? Фарз мекунем, ки мо як усули асосӣ дорем:
public static void main(String[] args) {
String text = "Hello world!";
System.out.println(text);
}
Навиштани қавӣ кафолат медиҳад, ки ҳангоми тартиб додани ин code, компилятор тафтиш мекунад, ки агар мо навъи тағирёбандаи матнро ҳамчун String муайян кунем, мо кӯшиш намекунем, ки онро дар ягон ҷо ҳамчун тағирёбандаи навъи дигар истифода барем (масалан, ҳамчун бутун) . Масалан, агар мо кӯшиш кунем, ки арзишро ба ҷои матн захира кунем 2L(яъне дароз ба ҷои String), мо дар вақти тартибдиҳӣ хато мегирем:

Main.java:3: error: incompatible types: long cannot be converted to String
String text = 2L;
Онхое. Навиштани қавӣ ба шумо имкон медиҳад, ки амалҳо дар an objectҳо танҳо вақте иҷро карда шаванд, ки ин амалиётҳо барои ин an objectҳо қонунӣ бошанд. Инро бехатарии навъи низ меноманд. Тавре ки дар JLS гуфта шудааст, дар Java ду категорияи намудҳо мавҷуданд: намудҳои ибтидоӣ ва намудҳои истинод. Шумо метавонед дар бораи намудҳои ибтидоӣ аз мақолаи барраси ба ёд оред: " Намудҳои ибтидоӣ дар Java: Онҳо он қадар ибтидоӣ нестанд ." Намудҳои истинодро метавон бо синф, интерфейс ё массив муаррифӣ кард. Ва имрӯз мо ба намудҳои истинод таваҷҷӯҳ хоҳем кард. Ва биёед бо массивҳо оғоз кунем:
class Main {
  public static void main(String[] args) {
    String[] text = new String[5];
    text[0] = "Hello";
  }
}
Ин code бе хато кор мекунад. Тавре ки мо медонем (масалан, аз " Oracle Java Tutorial: Массивҳо "), массив контейнерест, ки танҳо як намуди маълумотро нигоҳ медорад. Дар ин ҳолат - танҳо хатҳо. Биёед кӯшиш кунем, ки ба массив ба ҷои Сатр дароз илова кунем:
text[1] = 4L;
Биёед ин codeро иҷро кунем (масалан, дар Repl.it Online Java Compiler ) ва хатогӣ ба даст орем:
error: incompatible types: long cannot be converted to String
Массив ва бехатарии навъи забон ба мо имкон намедод, ки он чизеро, ки ба намуд мувофиқ набуд, дар массив захира кунем. Ин як зуҳури бехатарии навъи аст. Ба мо гуфтанд: "Хаторо ислоҳ кунед, аммо то он вақт ман codeро тартиб намедиҳам." Ва муҳимтар аз ҳама дар ин аст, ки ин дар вақти тартиб додан рӯй медиҳад, на ҳангоми оғози барнома. Яъне мо хатогиҳоро дарҳол мебинем, на “рӯзе”. Ва азбаски мо дар бораи массивҳо ёд кардем, биёед дар бораи чаҳорчӯбаи коллексияҳои Java низ ёдовар шавем . Мо дар он ҷо сохторҳои гуногун доштем. Масалан, рӯйхатҳо. Биёед мисолро аз нав нависед:
import java.util.*;
class Main {
  public static void main(String[] args) {
    List text = new ArrayList(5);
    text.add("Hello");
    text.add(4L);
    String test = text.get(0);
  }
}
testҲангоми тартиб додани он, мо дар хати оғозкунии тағирёбанда хато мегирем :
incompatible types: Object cannot be converted to String
Дар ҳолати мо, Рӯйхат метавонад ҳама гуна an objectро нигоҳ дорад (яъне an objectи навъи Object). Бинобар ин, мураттиб мегуяд, ки чунин бори масъулиятро ба души худ гирифта наметавонад. Аз ин рӯ, мо бояд ба таври возеҳ навъеро, ки мо аз рӯйхат мегирем, муайян кунем:
String test = (String) text.get(0);
Ин нишондод табдor намуд ё кастинги тип номида мешавад. Ва ҳама чиз ҳоло хуб кор хоҳад кард, то даме ки мо кӯшиш кунем, ки элементро дар индекси 1 ба даст орем, зеро он навъи Long аст. Ва мо хатои одилона мегирем, аммо аллакай вақте ки барнома кор мекунад (дар Runtime):

type conversion, typecasting
Exception in thread "main" java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String
Тавре ки мо мебинем, дар ин ҷо як қатор камбудиҳои муҳим мавҷуданд. Аввалан, мо маҷбур мешавем, ки арзиши аз рӯйхат гирифташударо ба синфи String "партоем". Розӣ, ин зишт аст. Сониян, дар сурати пайдо шудани хато, мо онро танҳо ҳангоми иҷро шудани барнома мебинем. Агар рамзи мо мураккабтар мебуд, мо метавонем дарҳол чунин хатогиро ошкор накунем. Ва таҳиягарон дар бораи он фикр карданд, ки чӣ гуна кор дар чунин ҳолатҳо осонтар ва рамз равшантар шавад. Ва онҳо таваллуд шуданд - Generics.
Генерикҳо барои гурбаҳо - 2

Умумӣ

Ҳамин тавр, генералҳо. Ин чист? Генералӣ як роҳи махсуси тавсифи навъҳои истифодашуда мебошад, ки тартибдиҳандаи code метавонад дар кори худ барои таъмини бехатарии намуд истифода барад. Чунин ба назар мерасад:
Генерикҳо барои гурбаҳо - 3
Дар ин ҷо як мисол ва шарҳи кӯтоҳ:
import java.util.*;
class Main {
  public static void main(String[] args) {
    List<String> text = new ArrayList<String>(5);
    text.add("Hello");
    text.add(4L);
    String test = text.get(1);
  }
}
Дар ин мисол, мо мегӯем, ки мо на танҳо List, балки дорем List, ки ТАНҲО бо an objectҳои навъи String кор мекунад. Ва дигарон не. Он чизе ки танҳо дар қавс нишон дода шудааст, мо метавонем онро захира кунем. Чунин «қавс»-ҳоро «қавсҳои кунҷӣ» меноманд, яъне. қавсҳои кунҷӣ. Тартибдиҳанда бо меҳрубонӣ моро тафтиш мекунад, ки оё мо ҳангоми кор бо рӯйхати сатрҳо ягон хатогӣ содир кардаем (рӯйхат матн ном дорад). Компилятор мебинад, ки мо бешармона кӯшиш мекунем, ки Лонгро ба рӯйхати сатр гузорем. Ва дар вақти тартибдиҳӣ он хатогӣ медиҳад:
error: no suitable method found for add(long)
Шумо шояд дар хотир дошта бошед, ки String насли CharSequence аст. Ва қарор кунед, ки коре кунед:
public static void main(String[] args) {
	ArrayList<CharSequence> text = new ArrayList<String>(5);
	text.add("Hello");
	String test = text.get(0);
}
Аммо ин имконнопазир аст ва мо хатогиро мегирем: error: incompatible types: ArrayList<String> cannot be converted to ArrayList<CharSequence> Ин аҷиб менамояд, зеро. сатр CharSequence sec = "test";ягон хатоги надорад. Биёед инро фаҳмем. Онҳо дар бораи ин рафтор мегӯянд: "Генерикҳо инвариант мебошанд." "Инвариант" чист? Ба ман маъқул аст, ки чӣ тавр дар ин бора дар Википедиа дар мақолаи " Коварианс ва контрварианс " гуфта шудааст:
Генерикҳо барои гурбаҳо - 4
Ҳамин тариқ, Инвариантӣ мавҷуд набудани мерос байни намудҳои ҳосилшуда мебошад. Агар Гурба зернамуди Ҳайвонҳо бошад, пас Маҷмӯа<Гурбаҳо> зернавъи Маҷмӯа<Ҳайвонот> ва Маҷмӯа<Ҷайвонҳо> зернамуди Маҷмӯа<Гурбаҳо> нестанд. Дар омади гап, бояд гуфт, ки аз Java SE 7 сар карда, ба истилоҳ " Оператори Diamond " пайдо шуд. Зеро ду қавсаи кунҷӣ <> ба алмос монанданд. Ин ба мо имкон медиҳад, ки генерикҳоро чунин истифода барем:
public static void main(String[] args) {
  List<String> lines = new ArrayList<>();
  lines.add("Hello world!");
  System.out.println(lines);
}
Дар асоси ин code, компилятор мефаҳмад, ки агар мо дар тарафи чап нишон дода бошем, ки он Listдорои an objectҳои навъи String аст, пас дар тарафи рост маънои онро дорад, ки мо мехоҳем linesArrayList-и навро ба тағирёбанда захира кунем, ки он an objectро низ нигоҳ медорад. навъи дар тарафи чап нишондодашуда. Ҳамин тавр, компилятор аз тарафи чап навъи тарафи ростро мефаҳмад ё хулоса мебарорад. Аз ин рӯ, ин рафторро дар забони англисӣ хулосаи навъи ё "Type Inference" меноманд. Боз як чизи ҷолибе, ки бояд қайд кард, намудҳои RAW ё "навъҳои хом" мебошад. Зеро Генерикҳо на ҳама вақт вуҷуд доштанд ва Java кӯшиш мекунад, ки мувофиқати ақибро то ҳадди имкон нигоҳ дорад, пас генерикҳо маҷбур мешаванд, ки бо кадом роҳе кор кунанд, ки дар он ҷо ягон генералӣ нишон дода нашудааст. Биёед як мисолро бубинем:
List<CharSequence> lines = new ArrayList<String>();
Тавре ки мо дар хотир дорем, чунин сатр аз сабаби тағйирнопазирии генерикҳо тартиб дода намешавад.
List<Object> lines = new ArrayList<String>();
Ва ин ҳам бо ҳамин сабаб тартиб дода намешавад.
List lines = new ArrayList<String>();
List<String> lines2 = new ArrayList();
Чунин сатрхо тартиб медиханд ва кор мекунанд. Маҳз дар онҳо Намудҳои Raw истифода мешаванд, яъне. намудҳои номаълум. Бори дигар бояд қайд кард, ки намудҳои хом набояд дар рамзи муосир истифода шаванд.
Генерикҳо барои гурбаҳо - 5

Синфҳои чопшуда

Ҳамин тавр, синфҳои чопшуда. Биёед бубинем, ки чӣ тавр мо метавонем синфи чопшудаи худро нависем. Масалан, мо иерархияи синф дорем:
public static abstract class Animal {
  public abstract void voice();
}

public static class Cat extends Animal {
  public void voice(){
    System.out.println("Meow meow");
  }
}

public static class Dog extends Animal {
  public void voice(){
    System.out.println("Woof woof");
  }
}
Мо мехоҳем синферо эҷод кунем, ки контейнери ҳайвонотро амалӣ кунад. Мумкин аст, ки синферо нависед, ки ҳама гуна Animal. Ин оддӣ, фаҳмо аст, АММО... сагу гурбаро омехта кардан бад аст, онҳо бо ҳамдигар дӯст нестанд. Гайр аз ин, агар касе чунин контейнер гирад, аз зарф иштибох карда гурбахоро ба як тудаи саг партофта метавонад... ва ин ба хайре намерасад. Ва дар ин ҷо генерикҳо ба мо кӯмак мекунанд. Масалан, биёед татбиқро чунин нависед:
public static class Box<T> {
  List<T> slots = new ArrayList<>();
  public List<T> getSlots() {
    return slots;
  }
}
Синфи мо бо an objectҳои намуде, ки бо номи генералии T муайян карда шудааст, кор хоҳад кард. Ин як навъ тахаллус аст. Зеро Генералӣ дар номи синф нишон дода шудааст, пас мо онро ҳангоми эълони синф қабул мекунем:
public static void main(String[] args) {
  Box<Cat> catBox = new Box<>();
  Cat murzik = new Cat();
  catBox.getSlots().add(murzik);
}
Тавре ки мо мебинем, мо нишон додем, ки мо дорем Box, ки танҳо бо Cat. Компилятор фаҳмид, ки catBoxба ҷои умумӣ, Tшумо бояд навъи онро Catдар ҳар ҷое, ки номи умумӣ нишон дода шудааст, иваз кунед T:
Генерикҳо барои гурбаҳо - 6
Онхое. ба шарофати Box<Cat>компилятор он мефаҳмад, ки slotsон воқеан бояд чӣ гуна бошад List<Cat>. Зеро Box<Dog>дар дохor он ҷо хоҳад буд slots, дорои List<Dog>. Дар эъломияи намуд метавонад якчанд генерикҳо мавҷуд бошанд, масалан:
public static class Box<T, V> {
Номи умумӣ метавонад ҳама чиз бошад, гарчанде ки тавсия дода мешавад, ки ба баъзе қоидаҳои ногуфта риоя кунед - "Конвенсияҳои номгузории параметрҳои навъи": Навъи элемент - E, навъи калид - K, навъи рақам - N, T - барои навъи, V - барои навъи арзиш . Дар омади гап, дар хотир доред, ки мо гуфта будем, ки генерикҳо инвариант мебошанд, яъне. иерархияи меросро нигох надоред. Дар асл, мо метавонем ба ин таъсир расонем. Яъне, мо имкон дорем, ки генерикҳои COvariant созем, яъне. бо як тартиб нигох доштани мерос. Ин рафтор "Намуди маҳдуд" номида мешавад, яъне. намудҳои маҳдуд. Масалан, синфи мо Boxметавонад ҳамаи ҳайвонотро дар бар гирад, пас мо як умумиро чунин эълон мекунем:
public static class Box<T extends Animal> {
Яъне, мо маҳдудияти болоиро ба синф муқаррар кардем Animal. Мо инчунин метавонем якчанд намудҳоро пас аз калимаи калидӣ муайян кунем extends. Ин маънои онро дорад, ки намуде, ки мо бо он кор хоҳем кард, бояд насли ягон синф бошад ва дар айни замон баъзе интерфейсро амалӣ созад. Барои намуна:
public static class Box<T extends Animal & Comparable> {
Дар ин ҳолат, агар мо кӯшиш кунем, ки Boxчизеро ба он гузорем, ки вориси нест Animalва иҷро намекунад Comparable, пас ҳангоми тартибдиҳӣ мо хатогиро мегирем:
error: type argument Cat is not within bounds of type-variable T
Генерикҳо барои гурбаҳо - 7

Усули чопкунӣ

Генерикҳо на танҳо дар намудҳо, балки дар усулҳои инфиродӣ низ истифода мешаванд. Истифодаи усулҳоро дар дастури расмӣ дидан мумкин аст: " Усулҳои Generics ".

Замина:

Генерикҳо барои гурбаҳо - 8
Биёед ба ин расм назар андозем. Тавре ки шумо мебинед, компилятор ба имзои метод менигарад ва мебинад, ки мо як синфи номуайянро ҳамчун вуруд мегирем. Он бо имзо муайян намекунад, ки мо ягон намуди an objectро бармегардонем, яъне. Объект. Аз ин рӯ, агар мо мехоҳем, масалан, ArrayList эҷод кунем, пас мо бояд ин корро кунем:
ArrayList<String> object = (ArrayList<String>) createObject(ArrayList.class);
Шумо бояд ба таври возеҳ нависед, ки натиҷа ArrayList хоҳад буд, ки зишт аст ва имкони хатогиро илова мекунад. Масалан, мо метавонем чунин сафсатаҳоро нависем ва он тартиб медиҳад:
ArrayList object = (ArrayList) createObject(LinkedList.class);
Оё мо метавонем ба компилятор кӯмак кунем? Бале, генерикҳо ба мо имкон медиҳанд, ки ин корро кунем. Биёед ба ҳамон мисол назар андозем:
Генерикҳо барои гурбаҳо - 9
Пас, мо метавонем an objectеро ба таври оддӣ созем:
ArrayList<String> object = createObject(ArrayList.class);
Генерикҳо барои гурбаҳо - 10

Корти ваҳшӣ

Мувофиқи дастури Oracle оид ба Generics, махсусан бахши " Ҷойгирҳо ", мо метавонем "навъи номаълум" -ро бо аломати савол тавсиф кунем. Wildcard як воситаи қулай барои кам кардани баъзе маҳдудиятҳои генерикҳо мебошад. Масалан, тавре ки мо қаблан муҳокима кардем, генерикҳо инвариант мебошанд. Ин маънои онро дорад, ки гарчанде ки ҳама синфҳо наслҳои (зернамудҳои) намуди Объект мебошанд, он List<любой тип>зернамуд нест List<Object>. ВАЛЕ, List<любой тип>он як зернамуд аст List<?>. Пас, мо метавонем рамзи зеринро нависем:
public static void printList(List<?> list) {
  for (Object elem: list) {
    System.out.print(elem + " ");
  }
  System.out.println();
}
Мисли генерикҳои муқаррарӣ (яъне бидуни истифодаи аломатҳои ҷонишин), генерикҳо бо аломатҳои ҷонишин метавонанд маҳдуд карда шаванд. Аломати ваҳшии маҳдуди боло шинос менамояд:
public static void printCatList(List<? extends Cat> list) {
  for (Cat cat: list) {
    System.out.print(cat + " ");
  }
  System.out.println();
}
Аммо шумо инчунин метавонед онро бо аломати ваҳшӣ маҳдуд маҳдуд кунед:
public static void printCatList(List<? super Cat> list) {
Ҳамин тариқ, усули қабули ҳама гурбаҳо, инчунин дар зинанизоми баландтар (то Объект) оғоз хоҳад кард.
Генерикҳо барои гурбаҳо - 11

Нест карданро нависед

Дар бораи генерикҳо сухан ронда, дар бораи "Навъи тозакунӣ" донистан лозим аст. Дарвоқеъ, тозакунии намуд дар бораи он аст, ки генерикҳо маълумот барои компилятор мебошанд. Ҳангоми иҷрои барнома, дигар маълумот дар бораи генерикҳо вуҷуд надорад, ки ин "тозакунӣ" номида мешавад. Ин тозакунӣ ба он таъсир мерасонад, ки навъи умумӣ бо навъи мушаххас иваз карда мешавад. Агар генералӣ сарҳад надошта бошад, он гоҳ навъи Объект иваз карда мешавад. Агар сарҳад муайян шуда бошад (масалан <T extends Comparable>), он иваз карда мешавад. Ин аст як мисол аз дастури Oracle: " Тозакунии намудҳои умумӣ ":
Генерикҳо барои гурбаҳо - 12
Тавре ки дар боло гуфта шуд, дар ин мисол генералӣ Tба сарҳади худ тоза карда мешавад, яъне. пеш аз Comparable.
Генерикҳо барои гурбаҳо - 13

Хулоса

Генерикҳо як мавзӯи хеле ҷолибанд. Умедворам ин мавзӯъ барои шумо ҷолиб аст. Барои ҷамъбаст, мо метавонем бигӯем, ки генерикҳо як воситаи олие мебошанд, ки таҳиягарон барои пешниҳоди компилятор бо маълумоти иловагӣ барои таъмини бехатарии намуд аз як тараф ва чандирӣ аз тарафи дигар гирифтаанд. Ва агар шумо таваҷҷӯҳ дошта бошед, ман тавсия медиҳам, ки захираҳоеро, ки ба ман маъқул буданд, санҷед: #Вячеслав
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION