JavaRush /Java Blog /Random-TL /Paggamit ng varargs kapag nagtatrabaho sa generics

Paggamit ng varargs kapag nagtatrabaho sa generics

Nai-publish sa grupo
Kamusta! Sa aralin ngayon ay magpapatuloy tayo sa pag-aaral ng generics. Nagkataon lang na ito ay isang malaking paksa, ngunit walang mapupuntahan - ito ay isang napakahalagang bahagi ng wika :) Kapag pinag-aralan mo ang dokumentasyon ng Oracle sa mga generic o nagbasa ng mga gabay sa Internet, makikita mo ang mga termino Mga Uri na Hindi Nare-reifiable at Mga Uri na Nare-reifiable . Anong uri ng salita ang "Reifiable"? Kahit na ang lahat ay mabuti sa Ingles, malamang na hindi mo ito nakilala. Subukan nating magsalin! Paggamit ng varargs kapag nagtatrabaho sa generics - 2
*salamat Google, marami kang natulungan -_-*
Ang reifiable-type ay isang uri na ang impormasyon ay ganap na magagamit sa runtime. Sa wikang Java, kabilang dito ang mga primitive, raw-type, at non-generic na uri. Sa kaibahan, ang Non-Reifiable Types ay mga uri na ang impormasyon ay nabubura at ginawang hindi available sa runtime. Ito ay mga generics lamang - List<String> , List<Integer> , atbp.

By the way, naaalala mo ba kung ano ang varargs ?

Kung sakaling nakalimutan mo, ito ay mga variable na haba ng argumento. Magagamit ang mga ito sa mga sitwasyon kung saan hindi natin alam kung gaano karaming mga argumento ang maaaring maipasa sa ating pamamaraan. Halimbawa, kung mayroon kaming klase ng calculator at mayroon itong pamamaraan sum. sum()Maaari kang magpasa ng 2 numero, 3, 5, o anumang bilang ng mga numero sa pamamaraan . Ito ay magiging lubhang kakaiba na labis na karga ang pamamaraan sa bawat oras sum()na isaalang-alang ang lahat ng posibleng mga pagpipilian. Sa halip, magagawa natin ito:
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));
   }
}
Output ng console:

15
11
Kaya, kapag ginamit varargssa kumbinasyon ng mga generic mayroong ilang mahahalagang tampok. Tingnan natin ang code na ito:
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")
       );
   }
}
Ang pamamaraan ay tumatagal ng isang listahan at anumang bilang ng mga bagay addAll()bilang input , at pagkatapos ay idaragdag ang lahat ng mga bagay na ito sa listahan. Sa pamamaraan na tinatawag namin ang aming pamamaraan nang dalawang beses . Sa unang pagkakataon na nagdagdag kami sa dalawang regular na linya. Maayos ang lahat dito. Sa pangalawang pagkakataon, nagdagdag kami ng dalawang bagay . At narito kami biglang nakakuha ng babala: List<E>Emain()addAll()ListListPair<String, String>

Unchecked generics array creation for varargs parameter
Ano ang ibig sabihin nito? Bakit tayo nakakatanggap ng babala at ano ang kinalaman nito array? Array- ito ay isang array, at walang mga arrays sa aming code! Magsimula tayo sa pangalawa. Binabanggit ng babala ang isang array dahil kino-convert ng compiler ang mga variable na haba ng argumento (varargs) sa isang array. Sa madaling salita, ang lagda ng aming pamamaraan ay addAll():
public static <E> void addAll(List<E> list, E... array)
Ito ay talagang ganito:
public static <E> void addAll(List<E> list, E[] array)
Iyon ay, sa pamamaraan main(), iko-convert ng compiler ang aming code sa ganito:
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")
        }
   );
}
Lahat ay maayos sa array String. Ngunit may isang array Pair<String, String>- hindi. Ang katotohanan ay Pair<String, String>ito ay isang Non-Reifiable Type. Sa panahon ng compilation, ang lahat ng impormasyon tungkol sa mga uri ng parameter (<String, String>) ay mabubura. Ang paggawa ng mga array mula sa Non-Reifiable Type ay hindi pinapayagan sa Java . Mabe-verify mo ito kung susubukan mong manu-manong gumawa ng array Pair<String, String>
public static void main(String[] args) {

   //  ошибка компиляции! Generic array creation
  Pair<String, String>[] array = new Pair<String, String>[10];
}
Ang dahilan ay malinaw - uri ng kaligtasan. Tulad ng naaalala mo, kapag gumagawa ng array, dapat mong ipahiwatig kung aling mga bagay (o primitives) ang iimbak ng array na ito.
int array[] = new int[10];
Sa isa sa mga nakaraang aralin, sinuri namin nang detalyado ang mekanismo ng pagbubura ng uri. Kaya, sa kasong ito, bilang resulta ng pagbubura ng mga uri, nawala ang impormasyon na ang Pairmga pares ay nakaimbak sa aming mga bagay <String, String>. Magiging hindi ligtas ang paggawa ng array. Kapag gumagamit ng mga pamamaraan na may varargsat generics, tiyaking tandaan ang tungkol sa uri ng pagbura at eksakto kung paano ito gumagana. Kung lubos kang kumpiyansa sa code na iyong isinulat, at alam mong hindi ito magdudulot ng anumang problema, maaari mong huwag paganahin ang varargsmga babalang nauugnay dito gamit ang isang anotasyon@SafeVarargs
@SafeVarargs
public static <E> void addAll(List<E> list, E... array) {

   for (E element : array) {
       list.add(element);
   }
}
Kung idaragdag mo ang anotasyong ito sa iyong pamamaraan, hindi lalabas ang babalang naranasan namin kanina. Ang isa pang posibleng problema kapag pinagsama varargsang mga generic ay ang heap pollution. Paggamit ng varargs kapag nagtatrabaho sa generics - 4Maaaring mangyari ang kontaminasyon sa mga sumusunod na sitwasyon:
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));
   }
}
Output ng console:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Sa madaling salita, ang heap pollution ay isang sitwasyon kung saan ang mga bagay ng uri 1 ay dapat nasa heap А, ngunit ang mga bagay na may uri ay napupunta doon B, dahil sa mga error sa kaligtasan ng uri. Sa ating halimbawa ganito ang nangyayari. Una, gumawa kami ng Raw variable numbersat itinalaga ito ng generic na koleksyon ArrayList<Number>. Pagkatapos noon ay dinagdagan namin ang numero doon 1.
List<String> strings = numbers;
Sa linyang ito, sinubukan kaming bigyan ng babala ng compiler tungkol sa mga posibleng error sa pamamagitan ng pagbibigay ng babala na " Hindi na-check ang pagtatalaga... ", ngunit hindi namin ito pinansin. Bilang resulta, mayroon kaming generic na variable ng uri List<String>, na tumuturo sa isang generic na koleksyon ng uri ArrayList<Number>. Ang sitwasyong ito ay malinaw na maaaring humantong sa gulo! Ito ang nangyayari. Gamit ang aming bagong variable, nagdaragdag kami ng string sa koleksyon. Ang tambak ay nadumhan - nagdagdag muna kami ng isang numero at pagkatapos ay isang string sa na-type na koleksyon. Binalaan kami ng compiler, ngunit hindi namin pinansin ang babala nito, nakakatanggap ClassCastExceptionlamang ng mga resulta habang tumatakbo ang programa. Ano ang kinalaman nito varargs? Ang paggamit varargssa mga generic ay madaling humantong sa tambak na polusyon. Narito ang isang simpleng halimbawa:
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);
   }
}
Anong nangyayari dito? Dahil sa pagbubura ng uri, ang aming mga parameter sheet (tatawagin namin silang "mga sheet" sa halip na "mga listahan" para sa kaginhawahan) ay -
List<String>...stringsLists
- ay magiging isang hanay ng mga sheet - List[]na may hindi kilalang uri (huwag kalimutan na ang mga varargs ay nagiging isang regular na array bilang isang resulta ng compilation). Dahil dito, madali kaming makakagawa ng assignment sa isang variable Object[] arraysa unang linya ng pamamaraan - nabura na ang mga uri sa aming mga sheet! At ngayon mayroon kaming isang variable ng uri Object[], kung saan maaari kaming magdagdag ng kahit ano - lahat ng mga bagay sa Java ay nagmana mula sa Object! Sa ngayon mayroon lang kaming hanay ng mga string sheet. Ngunit salamat sa paggamit varargsat pagbura ng mga uri, madali kaming magdagdag ng isang sheet ng mga numero sa mga ito, na kung ano ang ginagawa namin. Bilang resulta, dinudumhan natin ang bunton sa pamamagitan ng paghahalo ng mga bagay na may iba't ibang uri. Ang resulta ay magiging parehong exception ClassCastExceptionkapag sinusubukang basahin ang isang string mula sa array. Output ng console:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
Ito ang mga hindi inaasahang kahihinatnan na maaaring magresulta sa paggamit ng isang tila simpleng mekanismo varargs:) At dito na nagtatapos ang ating lecture ngayon. Huwag kalimutang lutasin ang ilang problema, at kung mayroon kang natitirang oras at lakas, pag-aralan ang karagdagang literatura. Ang " Effective Java " ay hindi magbabasa mismo! :) See you!
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION