JavaRush /Java Blogu /Random-AZ /Generiklərlə işləyərkən vararqlardan istifadə

Generiklərlə işləyərkən vararqlardan istifadə

Qrupda dərc edilmişdir
Salam! Bugünkü dərsimizdə generikləri öyrənməyə davam edəcəyik. Elə olur ki, bu, böyük mövzudur, amma getmək üçün heç bir yer yoxdur - bu dilin son dərəcə vacib hissəsidir :) Generiklər üzrə Oracle sənədlərini öyrəndiyiniz zaman və ya İnternetdə bələdçiləri oxuduğunuzda, şərtlərlə qarşılaşacaqsınız. Qeyri-reifiable növlərireifiable növləri . “Reifiable” hansı sözdür? İngilis dilində hər şey yaxşı olsa belə, çətin ki, onunla tanış olasınız. Gəlin tərcümə etməyə çalışaq! Generiklərlə işləyərkən vararqlardan istifadə - 2
*təşəkkürlər Google, çox kömək etdin -_-*
Reifiable tip, məlumatı iş vaxtında tam olaraq mövcud olan bir növdür. Java dilində bunlara primitivlər, xam tiplər və ümumi olmayan tiplər daxildir. Bunun əksinə olaraq, Reifiable Növlər məlumatı silinən və icra zamanı əlçatan olmayan növlərdir. Bunlar sadəcə ümumidir - List<String> , List<Integer> və s.

Yeri gəlmişkən, vararqların nə olduğunu xatırlayırsınız ?

Əgər unutmusunuzsa, bunlar dəyişən uzunluqlu arqumentlərdir. Onlar bizim metodumuza nə qədər arqumentin ötürülə biləcəyini dəqiq bilmədiyimiz vəziyyətlərdə faydalı olur. Məsələn, kalkulyator sinifimiz varsa və onun metodu varsa sum. Siz metoda sum()2 ədəd, 3, 5 və ya istədiyiniz qədər keçə bilərsiniz . sum()Bütün mümkün variantları nəzərə almaq üçün hər dəfə metodu həddindən artıq yükləmək çox qəribə olardı . Bunun əvəzinə bunu edə bilərik:
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));
   }
}
Konsol çıxışı:

15
11
Beləliklə, generiklərlə birlikdə istifadə edildikdə varargsbəzi vacib xüsusiyyətlər var. Bu koda baxaq:
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")
       );
   }
}
Metod siyahı və istənilən sayda obyekti addAll()giriş kimi götürür və sonra bütün bu obyektləri siyahıya əlavə edir. Metodda metodumuzu iki dəfə çağırırıq . İlk dəfə iki müntəzəm sətir əlavə edirik. Burada hər şey yaxşıdır. İkinci dəfə iki obyekt əlavə edirik . Və burada birdən bir xəbərdarlıq alırıq: List<E>Emain()addAll()ListListPair<String, String>

Unchecked generics array creation for varargs parameter
Bunun mənası nədi? Niyə xəbərdarlıq alırıq və bunun bununla nə əlaqəsi var array? Array- bu massivdir və kodumuzda heç bir massiv yoxdur! İkincidən başlayaq. Xəbərdarlıq massivdən bəhs edir, çünki kompilyator dəyişən uzunluqlu arqumentləri (varargs) massiləyə çevirir. Başqa sözlə, metodumuzun imzası addAll():
public static <E> void addAll(List<E> list, E... array)
Əslində belə görünür:
public static <E> void addAll(List<E> list, E[] array)
Yəni metodda main()kompilyator kodumuzu buna çevirəcək:
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")
        }
   );
}
Massivlə hər şey qaydasındadır String. Ancaq bir sıra ilə Pair<String, String>- yox. Fakt budur ki, Pair<String, String>bu, Reifiable Tipdir. Kompilyasiya zamanı parametr növləri (<String, String>) haqqında bütün məlumatlar silinəcək. Java-da Qeyri-Reifiable Tipdən massivlərin yaradılmasına icazə verilmir . Cüt<String, String> massivini əl ilə yaratmağa cəhd etsəniz, bunu yoxlaya bilərsiniz
public static void main(String[] args) {

   //  ошибка компиляции! Generic array creation
  Pair<String, String>[] array = new Pair<String, String>[10];
}
Səbəb aydındır - tipli təhlükəsizlik. Xatırladığınız kimi, massiv yaradarkən bu massivin hansı obyektləri (və ya primitivləri) saxlayacağını göstərməlisiniz.
int array[] = new int[10];
Əvvəlki dərslərdən birində növün silinməsi mexanizmini ətraflı araşdırdıq. Beləliklə, bu vəziyyətdə növlərin silinməsi nəticəsində biz Paircütlərin obyektlərimizdə saxlandığı məlumatını itirdik <String, String>. Massiv yaratmaq təhlükəli olacaq. və generiklərlə metodlardan istifadə edərkən varargs, növün silinməsi və onun necə işlədiyini xatırladığınızdan əmin olun. Yazdığınız koda tam əminsinizsə və bunun heç bir problem yaratmayacağını bilirsinizsə, varargsannotasiyadan istifadə edərək onunla əlaqəli xəbərdarlıqları söndürə bilərsiniz.@SafeVarargs
@SafeVarargs
public static <E> void addAll(List<E> list, E... array) {

   for (E element : array) {
       list.add(element);
   }
}
Bu annotasiyanı metodunuza əlavə etsəniz, əvvəllər qarşılaşdığımız xəbərdarlıq görünməyəcək. Jenerikləri birlikdə istifadə edərkən digər mümkün problem varargsyığın çirklənməsidir. Generiklərlə işləyərkən vararqlardan istifadə - 4Çirklənmə aşağıdakı hallarda baş verə bilər:
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));
   }
}
Konsol çıxışı:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Sadə dillə desək, yığın çirklənməsi 1-ci tip obyektlərin yığında olması lazım olduğu bir vəziyyətdir , lakin tip təhlükəsizlik xətalarına görə Аtipli obyektlər orada sona çatır . BBizim nümunəmizdə belə olur. Əvvəlcə biz Raw dəyişəni yaratdıq numbersvə ona ümumi kolleksiya təyin etdik ArrayList<Number>. Bundan sonra nömrəni ora əlavə etdik 1.
List<String> strings = numbers;
Bu sətirdə kompilyator “ Yoxlanılmamış tapşırıq... ” xəbərdarlığını verməklə bizi mümkün səhvlər barədə xəbərdar etməyə çalışdı , lakin biz buna məhəl qoymadıq. Nəticə olaraq, List<String>ümumi tip kolleksiyasına işarə edən ümumi tip dəyişənimiz var ArrayList<Number>. Bu vəziyyət açıq şəkildə problemə səbəb ola bilər! Bu baş verir. Yeni dəyişənimizdən istifadə edərək kolleksiyaya sətir əlavə edirik. Yığın çirkləndi - yığılmış kolleksiyaya əvvəlcə nömrə, sonra isə sətir əlavə etdik. Kompilyator bizi xəbərdar etdi, lakin biz onun xəbərdarlığına məhəl qoymadıq, nəticəni ClassCastExceptionyalnız proqram işləyərkən aldıq. Bununla nə əlaqəsi var varargs? Jeneriklərlə istifadə asanlıqla yığın çirklənməsinə səbəb ola bilər. varargs Budur sadə bir nümunə:
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);
   }
}
Burda nə baş verir? Növün silinməsi səbəbindən parametr vərəqlərimiz (rahatlıq üçün onları "siyahılar" əvəzinə "vərəqlər" adlandıracağıq) -
List<String>...stringsLists
- vərəqlər massivinə çevriləcək - List[]naməlum tipli (unutmayın ki, vararqlar kompilyasiya nəticəsində adi massivə çevrilir). Bu səbəbdən, metodun birinci sətirində dəyişənə asanlıqla tapşırıq verə bilərik Object[] array- növlər vərəqlərimizdən silindi! Object[]İndi bizdə hər hansı bir şeyi əlavə edə biləcəyimiz tip dəyişəni var - Java-dakı bütün obyektlər ondan miras qalır Object! Hal-hazırda bizdə yalnız bir sıra simli vərəqlər var. Ancaq növlərin istifadəsi varargsvə silinməsi sayəsində biz onlara asanlıqla bir vərəq nömrə əlavə edə bilərik, bunu da edirik. Nəticədə müxtəlif tipli obyektləri qarışdıraraq yığını çirkləndiririk. ClassCastExceptionMassivdən sətir oxumağa çalışarkən nəticə eyni istisna olacaq . Konsol çıxışı:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Sadə görünən mexanizmdən istifadə nəticəsində yarana biləcək gözlənilməz nəticələr bunlardır varargs:) Və bugünkü mühazirəmiz burada sona çatır. Bir neçə problemi həll etməyi unutmayın və vaxtınız və enerjiniz varsa, əlavə ədəbiyyatı öyrənin. “ Effektiv Java ” özünü oxumayacaq! :) Görüşənədək!
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION