JavaRush /Java блогу /Random-KY /Генериктер менен иштөөдө varargs колдонуу

Генериктер менен иштөөдө varargs колдонуу

Группада жарыяланган
Салам! Бүгүнкү сабакта биз генериктерди изилдөөнү улантабыз. Ошентип, бул чоң тема, бирок бара турган жери жок - бул тилдин өтө маанилүү бөлүгү :) Генериктер боюнча Oracle documentациясын изилдегенде же Интернеттен гиддерди окуганда, сиз терминдерди кезиктиресиз. Кайталанууга болбой турган түрлөрү жана кайра каралуучу түрлөрү . "Reifable" деген кандай сөз? Англис тorнде баары жакшы болсо да, сиз аны жолуктурбайсыз. Келгиле, которууга аракет кылалы! Генериктер менен иштөөдө varargs колдонуу - 2
*рахмат Google, сиз көп жардам бердиңиз -_-*
Кайталануучу тип - бул маалымат иштөө убагында толук жеткorктүү болгон тип. Java тorнде аларга примитивдер, чийки типтер жана жалпы эмес типтер кирет. Ал эми, Reifiable Түрлөр - бул маалымат өчүрүлүп, иштөө убагында жеткorксиз болуп калган типтер. Булар жөн гана генериктер - List<String> , List<Integer> ж.б.

Баса, варарг деген эмне экени эсиңиздеби ?

Эгер унутуп калган болсоңуз, булар өзгөрүлмө узундуктагы аргументтер. Алар биздин методубузга канча аргументтер берилээрин так билбеген кырдаалдарда пайдалуу. Мисалы, бизде калькулятор классы бар болсо жана анын методу бар sum. Методго sum()2 санды, 3, 5 же каалаганыңызды бере аласыз . sum()Бардык мүмкүн болгон варианттарды эске алуу үчүн ар бир жолу ыкмасын ашыкча жүктөө абдан кызык болмок . Анын ордуна биз муну кыла алабыз:
public class SimpleCalculator {

   public static int sum(int...numbers) {

       int result = 0;

       for(int i : numbers) {

           result += i;
       }

       return result;
   }

   public static void main(String[] args) {

       System.out.println(sum(1,2,3,4,5));
       System.out.println(sum(2,9));
   }
}
Консолдук чыгаруу:

15
11
Ошентип, varargsгенериктер менен айкалыштыруу кээ бир маанилүү өзгөчөлүктөргө ээ. Бул codeду карап көрөлү:
import javafx.util.Pair;
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static <E> void addAll(List<E> list, E... array) {

       for (E element : array) {
           list.add(element);
       }
   }

   public static void main(String[] args) {
       addAll(new ArrayList<String>(),  //  здесь все нормально
               "Leonardo da Vinci",
               "Vasco de Gama"
       );

       // а здесь мы получаем предупреждение
       addAll(new ArrayList<Pair<String, String>>(),
               new Pair<String, String>("Leonardo", "da Vinci"),
               new Pair<String, String>("Vasco", "de Gama")
       );
   }
}
Метод тизмени жана каалаган сандагы an objectтерди addAll()киргизүү катары алат , андан кийин бул an objectтердин баарын тизмеге кошот. Методдо биз методубузду эки жолу чакырабыз . Биринчи жолу биз эки кадимки саптарды кошобуз . Бул жерде баары жакшы. Экинчи жолу биз эки an objectти кошобуз . Бул жерде биз күтүлбөгөн жерден эскертүү алабыз: List<E>Emain()addAll()ListListPair<String, String>

Unchecked generics array creation for varargs parameter
Бул эмнени билдирет? Биз эмне үчүн эскертүү алабыз жана анын ага кандай тиешеси бар array? Array- бул массив жана биздин codeдо массивдер жок! Экинчиден баштайлы. Эскертүүдө массив айтылат, анткени компилятор өзгөрмө узундуктагы аргументтерди (varargs) массивге айлантат. Башка сөз менен айтканда, биздин ыкма кол болуп саналат addAll():
public static <E> void addAll(List<E> list, E... array)
Бул чындыгында мындай көрүнөт:
public static <E> void addAll(List<E> list, E[] array)
Башкача айтканда, методдо main(), компилятор биздин codeду ушуга айландырат:
public static void main(String[] args) {
   addAll(new ArrayList<String>(),
      new String[] {
        "Leonardo da Vinci",
        "Vasco de Gama"
      }
   );
   addAll(new ArrayList<Pair<String,String>>(),
        new Pair<String,String>[] {
            new Pair<String,String>("Leonardo","da Vinci"),
            new Pair<String,String>("Vasco","de Gama")
        }
   );
}
Массив менен баары жакшы String. Бирок массив менен Pair<String, String>- ​​жок. Чындыгында, Pair<String, String>бул Reifiable түрү. Компиляция учурунда параметр түрлөрү (<Стринг, Стрин>) жөнүндө бардык маалыматтар өчүрүлөт. Java'да Reifiable типтен массивдерди түзүүгө жол берилбейт . Эгер сиз Pair<String, String> массивин кол менен түзүүгө аракет кылсаңыз, муну текшере аласыз
public static void main(String[] args) {

   //  ошибка компиляции! Generic array creation
  Pair<String, String>[] array = new Pair<String, String>[10];
}
Себеби ачык-айкын - түрү коопсуздук. Эсиңизде болсо, массивди түзүүдө бул массив кайсы an objectтерди (же примитивдерди) сактай турганын көрсөтүшүңүз керек.
int array[] = new int[10];
Мурунку сабактардын биринде биз түрүн өчүрүү механизмин майда-чүйдөсүнө чейин карап чыктык. Ошентип, бул учурда, түрлөрүн өчүрүүнүн натыйжасында, биз Pairжуптар an objectтерибизде сакталган маалыматты жоготтук <String, String>. Массив түзүү кооптуу болот. жана генериктери менен методдорун колдонууда varargs, түрүн өчүрүү жана анын кантип иштээрин унутпаңыз. Эгер сиз жазган codeуңузга толук ишенсеңиз жана ал эч кандай көйгөй жаратпай турганын билсеңиз, varargsannotationны колдонуу менен ага байланыштуу эскертүүлөрдү өчүрө аласыз.@SafeVarargs
@SafeVarargs
public static <E> void addAll(List<E> list, E... array) {

   for (E element : array) {
       list.add(element);
   }
}
Эгер сиз бул annotationны ыкмаңызга кошсоңуз, анда биз мурда жолуккан эскертүү көрүнбөйт. Генериктерди чогуу колдонууда дагы бир мүмкүн болгон көйгөй varargsбул үймөктүн булганышы. Генериктер менен иштөөдө varargs колдонуу - 4Булгануу төмөнкү учурларда пайда болушу мүмкүн:
import java.util.ArrayList;
import java.util.List;

public class Main {

   static List<String> makeHeapPollution() {
       List numbers = new ArrayList<Number>();
       numbers.add(1);
       List<String> strings = numbers;
       strings.add("");
       return strings;
   }

   public static void main(String[] args) {

       List<String> stringsWithHeapPollution = makeHeapPollution();

       System.out.println(stringsWithHeapPollution.get(0));
   }
}
Консолдук чыгаруу:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Жөнөкөй сөз менен айтканда, үймөктүн булганышы – бул 1-типтеги an objectтер үймөктө болушу керек болгон кырдаал , бирок типтеги an objectтер типтеги коопсуздук каталарынан улам Аошол жерде аяктайт . BБиздин мисалда ушундай болот. Алгач биз Raw өзгөрмөсүн түзүп numbers, ага жалпы коллекция ыйгардык ArrayList<Number>. Андан кийин биз ал жерге номерди коштук 1.
List<String> strings = numbers;
Бул сапта компилятор “ Текшерилбеген тапшырма... ” эскертүүсүн берип, мүмкүн болгон каталар жөнүндө эскертүүгө аракет кылды , бирок биз ага көңүл бурбай койдук. Натыйжада, бизде List<String>типтин жалпы жыйындысын көрсөткөн жалпы өзгөрмө бар ArrayList<Number>. Бул жагдай ачык эле кыйынчылыкка алып келиши мүмкүн! Бул эмне болот. Жаңы өзгөрмөбүздү колдонуп, коллекцияга сап кошобуз. Үймөк булганган - терилген коллекцияга адегенде санды, анан сапты коштук. Компилятор бизге эскертти, бирок биз анын эскертүүсүнө көңүл бурбай, ClassCastExceptionпрограмма иштеп жатканда гана жыйынтыктарды алдык. Анын эмне менен байланышы бар varargs? Генериктери менен колдонуу varargsоңой булганууга алып келиши мүмкүн. Бул жерде жөнөкөй мисал:
import java.util.Arrays;
import java.util.List;

public class Main {

   static void makeHeapPollution(List<String>... stringsLists) {
       Object[] array = stringsLists;
       List<Integer> numbersList = Arrays.asList(66,22,44,12);

       array[0] = numbersList;
       String str = stringsLists[0].get(0);
   }

   public static void main(String[] args) {

       List<String> cars1 = Arrays.asList("Ford", "Fiat", "Kia");
       List<String> cars2 = Arrays.asList("Ferrari", "Bugatti", "Zaporozhets");

       makeHeapPollution(cars1, cars2);
   }
}
Бул жакта эмне болуп жатат? Типти өчүрүүдөн улам, биздин параметр баракчаларыбыз (ынгайлуу болуу үчүн аларды "тизмелердин" ордуна "баракчалар" деп атайбыз) -
List<String>...stringsLists
- барактардын массивине айланат - List[]белгисиз түрдөгү (varargs компиляциянын натыйжасында кадимки массивге айланарын унутпаңыз). Ушундан улам, биз ыкманын биринчи сабында өзгөрмөгө оңой тапшырма бере алабыз Object[] array- түрлөрү биздин баракчалардан өчүрүлдү! Эми бизде типтеги өзгөрмө бар Object[], ага биз каалаган нерсени кошо алабыз - Javaдагы бардык an objectтер мураска алат Object! Азыр бизде сап барактарынын массивдери гана бар. Бирок түрлөрүн колдонуунун varargsжана өчүрүүнүн аркасында биз аларга сандар барагын оңой эле кошо алабыз, муну биз жасайбыз. Натыйжада ар кандай типтеги an objectилерди аралаштырып үймөктү булгап жатабыз. ClassCastExceptionНатыйжа массивден сапты окууга аракет кылганда эле өзгөчө болот . Консолдук чыгаруу:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Жөнөкөй көрүнгөн механизмди колдонуунун күтүлбөгөн кесепеттери мына ушунда varargs:) Мына ушуну менен бүгүнкү лекциябыз аяктайт. Бир нече маселелерди чечүүнү унутпаңыз, эгер сизде убакыт жана күч болсо, кошумча адабияттарды изилдеңиз. " Эффективдүү Java " өзүн окуbyte! :) Көрүшкөнчө!
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION