JavaRush /Блоги Java /Random-TG /Рамзҳои ҷодугарӣ дар Java Generics

Рамзҳои ҷодугарӣ дар Java Generics

Дар гурӯҳ нашр шудааст
Салом! Мо омӯзиши мавзӯи генералиро идома медиҳем. Шумо аллакай дар бораи онҳо аз лексияҳои қаблӣ маълумоти хуб доред (дар бораи истифодаи varargs ҳангоми кор бо генерикҳо ва дар бораи тозакунии навъи ), аммо мо то ҳол як мавзӯи муҳимро фаро нагирифтаем: аломатҳои ҷонишин . Ин хусусияти хеле муҳими генерикҳо мебошад. Ба дарачае, ки мо барои он лекцияи алохида бахшидаем! Бо вуҷуди ин, дар бораи аломатҳои ҷодугарӣ ҳеҷ чизи мушкиле нест, шумо ҳоло хоҳед дид :) Рамзҳои ҷодугарӣ дар умумӣ - 1Биёед ба мисол нигаред:
public class Main {

   public static void main(String[] args) {

       String str = new String("Test!");
       // ниHowих проблем
       Object obj = str;

       List<String> strings = new ArrayList<String>();
       // ошибка компиляции!
       List<Object> objects = strings;
   }
}
Дар ин ҷо чӣ гап? Мо ду ҳолати ба ҳам монандро мебинем. Дар аввалини инҳо, мо кӯшиш мекунем, ки an objectро Stringба чоп гузорем Object. Бо ин мушкилот нест, ҳама чиз тавре кор мекунад, ки лозим аст. Аммо дар ҳолати дуюм, компилятор хато мекунад. Ҳарчанд чунин ба назар мерасад, ки мо ҳамин корро карда истодаем. Ин танҳо он аст, ки ҳоло мо коллексияи якчанд an objectро истифода мебарем. Аммо чаро хатогӣ рух медиҳад? Фарқият дар чист, ки оё мо як an objectро Stringба як намуд меандозем Objectё 20 an object? Байни an object ва маҷмӯи an objectҳо фарқияти муҳим вуҷуд дорад . Агар синф Bвориси синф бошад А, Collection<B>вориси синф нест Collection<A>. Аз ин сабаб мо натавонистем List<String>ба List<Object>. Stringворис аст Object, вале List<String>ворисон нест List<Object>. Интуитивӣ, ин чандон мантиқӣ ба назар намерасад. Чаро офарандагони забон ин принципро ба рохбарй гирифтаанд? Биёед тасаввур кунем, ки компилятор дар ин ҷо ба мо хато намекунад:
List<String> strings = new ArrayList<String>();
List<Object> objects = strings;
Дар ин ҳолат, мо метавонем, масалан, амалҳои зеринро иҷро кунем:
objects.add(new Object());
String s = strings.get(0);
Азбаски компилятор ба мо хато накард ва ба мо иҷозат дод, ки истинод List<Object> objectба коллексияи сатрҳо созем strings, мо метавонем stringsна сатр, балки ҳама гуна an objectро илова кунем Object! Ҳамин тариқ, мо кафолати онро аз даст додем, ки дар коллексияи мо танҳо an objectҳои дар умумӣ зикршуда мавҷудандString . Яъне мо бартарии асосии генерикхо — бехатарии типро аз даст додем. Ва азбаски компилятор ба мо имкон дод, ки ҳамаи ин корро анҷом диҳем, ин маънои онро дорад, ки мо танҳо ҳангоми иҷрои барнома хато мегирем, ки ин ҳамеша аз хатогии компиляция хеле бадтар аст. Барои пешгирии чунин ҳолатҳо, компилятор ба мо хато медиҳад:
// ошибка компиляции
List<Object> objects = strings;
...ва ба ӯ хотиррасон мекунад, ки List<String>ӯ ворисон нест List<Object>. Ин як қоидаи оҳанин барои амалиёти генерикҳо аст ва ҳангоми истифодаи онҳо бояд дар хотир дошта бошад. Биёед пеш равем. Фарз мекунем, ки мо иерархияи хурди синф дорем:
public class Animal {

   public void feed() {

       System.out.println("Animal.feed()");
   }
}

public class Pet extends Animal {

   public void call() {

       System.out.println("Pet.call()");
   }
}

public class Cat extends Pet {

   public void meow() {

       System.out.println("Cat.meow()");
   }
}
Дар сари иерархия танҳо Ҳайвонот ҳастанд: Ҳайвоноти хонагӣ аз онҳо мерос гирифта мешаванд. Ҳайвоноти хонагӣ ба 2 намуд тақсим мешаванд - Сагон ва Гурбаҳо. Акнун тасаввур кунед, ки мо бояд як усули оддӣ эҷод кунем iterateAnimals(). Усул бояд маҷмӯаи ҳама гуна ҳайвонотро ( Animal, , Pet, , , , , , , , , , , Cat, Dog, , , , , , , , , , , , , , , , , , . Биёед кӯшиш кунем, ки ин усулро нависем:
public static void iterateAnimals(Collection<Animal> animals) {

   for(Animal animal: animals) {

       System.out.println("Еще один шаг в цикле пройден!");
   }
}
Чунин ба назар мерасад, ки мушкилот ҳал шудааст! Аммо, чунон ки мо ба наздикӣ фаҳмидем, List<Cat>ё List<Dog>ворисон List<Pet>нестанд List<Animal>! Аз ин рӯ, вақте ки мо кӯшиш мекунем, ки усулро iterateAnimals()бо рӯйхати гурбаҳо даъват кунем, мо хатои компиляторро мегирем:
import java.util.*;

public class Main3 {


   public static void iterateAnimals(Collection<Animal> animals) {

       for(Animal animal: animals) {

           System.out.println("Еще один шаг в цикле пройден!");
       }
   }

   public static void main(String[] args) {


       List<Cat> cats = new ArrayList<>();
       cats.add(new Cat());
       cats.add(new Cat());
       cats.add(new Cat());
       cats.add(new Cat());

       //ошибка компилятора!
       iterateAnimals(cats);
   }
}
Вазъият барои мо хуб нест! Маълум мешавад, ки барои ба хисоб гирифтани хамаи намудхои хайвонот усулхои алохида навиштан лозим меояд? Дар асл, не, ба шумо лозим нест :) Ва аломатҳои ҷонишин ба мо дар ин кор кӯмак хоҳанд кард ! Мо мушкилотро дар як усули оддӣ бо истифода аз ин сохтмон ҳал мекунем:
public static void iterateAnimals(Collection<? extends Animal> animals) {

   for(Animal animal: animals) {

       System.out.println("Еще один шаг в цикле пройден!");
   }
}
Ин аломати ваҳшӣ аст. Аниқтараш, ин аввалин аз якчанд намуди аломатҳои ҷодугарӣ аст - “ extends ” (номи дигар аст Upper Bounded Wildcards ). Ин тарҳ ба мо чӣ мегӯяд? Ин маънои онро дорад, ки усул ҳамчун вуруд маҷмӯи an objectҳои синф Animalё an objectҳои ҳама гуна синфи наслиро мегирад Animal (? extends Animal). AnimalБа ибораи дигар, усул метавонад коллексияи , Pet, Dogё ҳамчун вурудро қабул кунад Cat- ин фарқият надорад. Биёед боварӣ ҳосил кунем, ки ин кор мекунад:
public static void main(String[] args) {

   List<Animal> animals = new ArrayList<>();
   animals.add(new Animal());
   animals.add(new Animal());

   List<Pet> pets = new ArrayList<>();
   pets.add(new Pet());
   pets.add(new Pet());

   List<Cat> cats = new ArrayList<>();
   cats.add(new Cat());
   cats.add(new Cat());

   List<Dog> dogs = new ArrayList<>();
   dogs.add(new Dog());
   dogs.add(new Dog());

   iterateAnimals(animals);
   iterateAnimals(pets);
   iterateAnimals(cats);
   iterateAnimals(dogs);
}
Натиҷаи консол:

Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Еще один шаг в цикле пройден!
Мо ҳамагӣ 4 коллексия ва 8 an objectро офаридаем ва дар консол маҳз 8 сабт мавҷуд аст. Ҳама чиз хуб кор мекунад! :) Нишони ваҳшӣ ба мо имкон дод, ки мантиқи заруриро бо пайвастшавӣ ба намудҳои мушаххас ба як усул ба осонӣ мувофиқ созем. Мо аз зарурати навиштани усули алохида барои хар як намуди хайвон халос шудем. Тасаввур кунед, ки агар замимаи мо дар боғи ҳайвонот ё клиникаи byteорӣ истифода мешуд, мо чанд усул медоштем :) Акнун биёед ба вазъияти дигар назар андозем. Иерархияи меросии мо бетағйир боқӣ мемонад: синфи сатҳи боло Animal, дар поён синфи Pets Petва дар сатҳи оянда Catва Dog. Акнун ба шумо лозим аст, ки усулро аз нав нависед iretateAnimals(), то он метавонад бо ҳама намуди ҳайвонот, ба истиснои сагҳо кор кунад . Collection<Animal>Яъне, он бояд қабул ё Collection<Pet>ҳамчун вуруд Collection<Cat>, аммо набояд бо Collection<Dog>. Чӣ тавр мо ба ин ноил шуда метавонем? Чунин ба назар мерасад, ки дурнамои навиштани усули алоҳида барои ҳар як намуд боз дар пеши назари мост:/ Дигар чӣ гуна мо мантиқи худро ба мураттиб фаҳмонем? Ва ин корро хеле содда кардан мумкин аст! Дар ин ҷо аломатҳои ваҳшӣ боз ба кӯмаки мо меоянд. Аммо ин дафъа мо навъи дигарро истифода хоҳем кард - “ super ” (номи дигар кортҳои поёнии маҳдудшуда аст ).
public static void iterateAnimals(Collection<? super Cat> animals) {

   for(int i = 0; i < animals.size(); i++) {

       System.out.println("Еще один шаг в цикле пройден!");
   }
}
Принсипи ин ҷо монанд аст. Сохтмон <? super Cat>ба компилятор мегӯяд, ки усул iterateAnimals()метавонад ҳамчун вуруд маҷмӯи an objectҳои синф Catё ягон синфи аҷдодии дигарро гирад Cat. CatДар мо худи синф , аҷдоди он - Petsва аҷдоди ниёгон ба ин тавсиф мувофиқат мекунанд Animal. Синф Dogба ин маҳдудият мувофиқат намекунад ва аз ин рӯ, кӯшиши истифодаи усул бо рӯйхат List<Dog>боиси хатои ҷамъоварӣ мегардад:
public static void main(String[] args) {

   List<Animal> animals = new ArrayList<>();
   animals.add(new Animal());
   animals.add(new Animal());

   List<Pet> pets = new ArrayList<>();
   pets.add(new Pet());
   pets.add(new Pet());

   List<Cat> cats = new ArrayList<>();
   cats.add(new Cat());
   cats.add(new Cat());

   List<Dog> dogs = new ArrayList<>();
   dogs.add(new Dog());
   dogs.add(new Dog());

   iterateAnimals(animals);
   iterateAnimals(pets);
   iterateAnimals(cats);

   //ошибка компиляции!
   iterateAnimals(dogs);
}
Мушкилоти мо ҳал шуд ва боз аломатҳои ҷобаҷоӣ хеле муфид шуданд :) Бо ин лексия анҷом меёбад. Акнун шумо мебинед, ки мавзӯи генерикҳо ҳангоми омӯзиши Java то чӣ андоза муҳим аст - мо дар он 4 лексия хондем! Аммо ҳоло шумо мавзӯъро хуб дарк кардаед ва метавонед дар мусоҳиба худро исбот кунед :) Ва ҳоло вақти бозгашт ба вазифаҳост! Дар таҳсилатон барори кор! :)
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION