JavaRush /Java блогы /Random-KK /Генериктермен жұмыс істеу кезінде varargs пайдалану

Генериктермен жұмыс істеу кезінде varargs пайдалану

Топта жарияланған
Сәлеметсіз бе! Бүгінгі сабақта біз генериктерді оқуды жалғастырамыз. Бұл үлкен тақырып, бірақ баратын жер жоқ - бұл тілдің өте маңызды бөлігі :) Генериктерге арналған Oracle құжаттамасын оқығанда немесе Интернетте нұсқаулықтарды оқығанда, сіз терминдерді кездестіресіз. Қайталанbyteын түрлер және қайталанатын түрлер . «Қайталанатын» сөздің қай түріне жатады? Ағылшын тілінде бәрі жақсы болса да, оны кездестіру екіталай. Аударып көрейік! Генериктермен жұмыс істеу кезінде varargs пайдалану - 2
*рахмет Google, сіз көп көмектестіңіз -_-*
Қайталанатын түрі - ақпараты орындалу уақытында толық қолжетімді болатын түрі. Java тілінде оларға примитивтер, raw-типтер және жалпы емес типтер жатады. Керісінше, Қайталанbyteын түрлер - ақпараты өшірілетін және орындау уақытында қолжетімсіз болатын түрлер. Бұл жай ғана генериктер - 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")
       );
   }
}
Әдіс тізімді және нысандардың кез келген санын addAll()кіріс ретінде қабылдайды , содан кейін осы нысандардың барлығын тізімге қосады. Әдісте біз әдісімізді екі рет шақырамыз . Бірінші рет біз екі тұрақты жолды қосамыз . Мұнда бәрі жақсы. Екінші рет біз екі нысанды қосамыз . Міне, біз кенеттен ескерту аламыз: 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>бұл қайталанbyteын түрі. Компиляция кезінде параметр түрлері (<Жол, Жол>) туралы барлық ақпарат жойылады. Java тілінде қайталанbyteын типтен массивтер жасауға рұқсат етілмейді . Pair<String, String> массивін қолмен жасауға әрекеттенсеңіз, мұны тексеруге болады
public static void main(String[] args) {

   //  ошибка компиляции! Generic array creation
  Pair<String, String>[] array = new Pair<String, String>[10];
}
Себебі анық - типті қауіпсіздік. Естеріңізде болса, массив құру кезінде бұл массив қандай нысандарды (немесе қарабайырларды) сақтайтынын көрсетуіңіз керек.
int array[] = new int[10];
Өткен сабақтардың бірінде біз типті өшіру механизмін егжей-тегжейлі қарастырдық. Осылайша, бұл жағдайда, типтерді өшіру нәтижесінде біз Pairжұптар біздің нысандарда сақталған ақпаратты жоғалттық <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- үйінділердің ластануы. Генериктермен жұмыс істегенде vararg қолдану - 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ілер үйіндіде болуы керек жағдай , бірақ типтегі нысандар қауіпсіздік қателеріне байланысты Асонда аяқталады . 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 тіліндегі барлық нысандар мұрагер Object! Дәл қазір бізде тек жол парақтары бар. Бірақ түрлерін пайдалану varargsжәне өшіру арқасында біз оларға сандар парағын оңай қоса аламыз, бұл біз жасаймыз. Нәтижесінде әртүрлі типтегі заттарды араластыру арқылы үйінді ластаймыз. ClassCastExceptionНәтиже массивтен жолды оқу әрекеті кезінде бірдей ерекшелік болады . Консоль шығысы:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Қарапайым болып көрінетін механизмді қолданудың күтпеген салдары осылар varargs:) Міне, біздің бүгінгі лекциямыз аяқталды. Бірнеше мәселені шешуді ұмытпаңыз, егер сізде уақыт пен күш қалса, қосымша әдебиеттерді оқыңыз. « Тиімді Java » өзін оқымайды! :) Кездескенше!
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION