JavaRush /Blog Jawa /Random-JV /Generik kanggo kucing
Viacheslav
tingkat

Generik kanggo kucing

Diterbitake ing grup
Generik kanggo kucing - 1

Pambuka

Dina iki minangka dina sing apik kanggo ngelingi apa sing kita ngerti babagan Jawa. Miturut dokumen sing paling penting, i.e. Spesifikasi Basa Jawa (JLS - Java Language Specifiaction), Basa Jawa iku basa kang ketik banget, kaya kang dijlentrehake ing bab “ Bab 4. Jinis, Nilai, lan Variabel “. Apa tegese iki? Ayo kita duwe metode utama:
public static void main(String[] args) {
String text = "Hello world!";
System.out.println(text);
}
Ketik sing kuat mesthekake yen kode iki dikompilasi, kompiler bakal mriksa yen kita nemtokake jinis variabel teks minangka String, mula kita ora nyoba nggunakake ing ngendi wae minangka variabel jinis liyane (contone, minangka Integer). . Contone, yen kita nyoba nyimpen nilai tinimbang teks 2L(yaiku dawa tinimbang String), kita bakal entuk kesalahan nalika kompilasi:

Main.java:3: error: incompatible types: long cannot be converted to String
String text = 2L;
Sing. Ngetik sing kuat ngidini sampeyan mesthekake yen operasi ing obyek ditindakake mung nalika operasi kasebut sah kanggo obyek kasebut. Iki uga disebut safety jinis. Kaya sing kasebut ing JLS, ana rong kategori jinis ing Jawa: jinis primitif lan jinis referensi. Sampeyan bisa ngelingi babagan jinis primitif saka artikel review: " Jinis primitif ing Jawa: Ora kaya primitif ." Jinis referensi bisa diwakili dening kelas, antarmuka, utawa larik. Lan dina iki kita bakal kasengsem ing jinis referensi. Lan ayo miwiti karo array:
class Main {
  public static void main(String[] args) {
    String[] text = new String[5];
    text[0] = "Hello";
  }
}
Kode iki mlaku tanpa kesalahan. Kita ngerti (contone, saka " Oracle Java Tutorial: Arrays "), array minangka wadhah sing nyimpen data mung siji jinis. Ing kasus iki - mung baris. Ayo nyoba nambah dawa menyang array tinimbang String:
text[1] = 4L;
Ayo mbukak kode iki (contone, ing Repl.it Online Java Compiler ) lan entuk kesalahan:
error: incompatible types: long cannot be converted to String
Array lan jinis safety saka basa ora ngidini kita kanggo nyimpen menyang Uploaded apa ora pas jinis. Iki minangka manifestasi saka jinis safety. Kita dikandhani: "Ndandani kesalahan, nanging nganti saiki aku ora bakal ngumpulake kode kasebut." Lan sing paling penting babagan iki yaiku kedadeyan kasebut nalika kompilasi, lan ora nalika program diluncurake. Yaiku, kita langsung ndeleng kesalahan, lan ora "ing sawijining dina". Lan amarga kita ngelingi babagan array, ayo elinga babagan Java Collections Framework . Kita duwe struktur sing beda-beda ing kana. Contone, dhaptar. Ayo nulis maneh conto:
import java.util.*;
class Main {
  public static void main(String[] args) {
    List text = new ArrayList(5);
    text.add("Hello");
    text.add(4L);
    String test = text.get(0);
  }
}
Nalika ngumpulake, kita bakal nampa testkesalahan ing baris initialization variabel:
incompatible types: Object cannot be converted to String
Ing kasus kita, List bisa nyimpen obyek apa wae (yaiku obyek saka jinis Obyek). Mulane, panyusun ujar manawa ora bisa nanggung beban tanggung jawab kasebut. Mulane, kita kudu kanthi tegas nemtokake jinis sing bakal kita entuk saka dhaptar:
String test = (String) text.get(0);
Indikasi iki diarani konversi jinis utawa casting jinis. Lan kabeh bakal bisa digunakake saiki nganti kita nyoba entuk unsur ing indeks 1, amarga iku saka jinis Long. Lan kita bakal entuk kesalahan sing adil, nanging nalika program lagi mlaku (ing Runtime):

type conversion, typecasting
Exception in thread "main" java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String
Kaya sing kita deleng, ana sawetara kekurangan penting ing kene. Kaping pisanan, kita dipeksa kanggo "cast" nilai sing dipikolehi saka dhaptar menyang kelas String. Setuju, iki ala. Kapindho, yen ana kesalahan, kita bakal weruh mung nalika program dieksekusi. Yen kode kita luwih rumit, kita bisa uga ora langsung ndeteksi kesalahan kasebut. Lan pangembang wiwit mikir babagan carane nggawe karya ing kahanan kaya mengkono luwih gampang lan kode luwih cetha. Lan padha lair - Generics.
Generik kanggo kucing - 2

Generik

Dadi, generik. Opo kuwi? A umum minangka cara khusus kanggo njlèntrèhaké jinis sing digunakake, sing bisa digunakake kompilator kode ing karya kanggo njamin safety jinis. Iku katon kaya iki:
Generik kanggo kucing - 3
Punika conto singkat lan panjelasan:
import java.util.*;
class Main {
  public static void main(String[] args) {
    List<String> text = new ArrayList<String>(5);
    text.add("Hello");
    text.add(4L);
    String test = text.get(1);
  }
}
Ing conto iki, kita ngomong yen kita duwe ora mung List, nanging List, sing ONLY dianggo karo obyek saka jinis String. Lan ora ana liyane. Apa mung dituduhake ing kurung, kita bisa nyimpen. "Kurung" kasebut diarani "kurung sudut", i.e. kurung sudut. Compiler bakal mriksa manawa kita nggawe kesalahan nalika nggarap dhaptar string (dhaptar kasebut diarani teks). Compiler bakal weruh sing kita brazenly nyoba kanggo nyelehake Long menyang dhaftar String. Lan ing wektu kompilasi bakal menehi kesalahan:
error: no suitable method found for add(long)
Sampeyan bisa uga wis ngelingi yen String minangka turunan saka CharSequence. Lan mutusake kanggo nindakake kaya:
public static void main(String[] args) {
	ArrayList<CharSequence> text = new ArrayList<String>(5);
	text.add("Hello");
	String test = text.get(0);
}
Nanging iki ora bisa lan kita bakal njaluk kesalahan: error: incompatible types: ArrayList<String> cannot be converted to ArrayList<CharSequence> Iku misale jek aneh, amarga. baris CharSequence sec = "test";ora ngandhut kasalahan. Ayo dadi tokoh metu. Dheweke ujar babagan prilaku iki: "Generik invarian." Apa sing "invarian"? Aku seneng babagan iki ing Wikipedia ing artikel " Kovarian lan kontravarian ":
Generik kanggo kucing - 4
Dadi, Invariance yaiku ora ana warisan antarane jinis turunan. Yen Kucing minangka subtipe saka Kewan, mula Set<Cats> dudu subtipe Set<Animals> lan Set<Animals> dudu subtipe Set<Cats>. Miturut cara, sampeyan kudu ujar manawa diwiwiti karo Java SE 7, sing diarani " Operator Diamond ". Amarga kurung sudut loro <> kaya inten. Iki ngidini kita nggunakake generik kaya iki:
public static void main(String[] args) {
  List<String> lines = new ArrayList<>();
  lines.add("Hello world!");
  System.out.println(lines);
}
Adhedhasar kode iki, compiler mangertos yen kita nuduhake ing sisih kiwa sing Listbakal ngemot obyek saka jinis String, banjur ing sisih tengen kita arep kanggo linesnyimpen ArrayList anyar menyang variabel, kang uga bakal nyimpen obyek. saka jinis kasebut ing sisih kiwa. Dadi compiler saka sisih kiwa mangertos utawa infers jinis kanggo sisih tengen. Mulane prilaku iki diarani tipe inferensi utawa "Tipe Inferensi" ing basa Inggris. Bab liyane sing menarik kanggo dicathet yaiku Jinis RAW utawa "jinis mentah". Amarga Generik wis ora tansah ana, lan Jawa nyoba kanggo njaga kompatibilitas sakdurunge sabisa, banjur generik dipeksa piye wae bisa karo kode ngendi ora generik kasebut. Ayo ndeleng conto:
List<CharSequence> lines = new ArrayList<String>();
Minangka kita elinga, baris kasebut ora bakal dikompilasi amarga invariance generik.
List<Object> lines = new ArrayList<String>();
Lan siji iki ora bakal ngumpulake, kanthi alasan sing padha.
List lines = new ArrayList<String>();
List<String> lines2 = new ArrayList();
Garis kasebut bakal dikompilasi lan bakal bisa digunakake. Iku ing wong-wong mau sing Jinis Raw digunakake, i.e. jinis unspecified. Sawise maneh, kudu dicathet yen Jinis Mentah ORA digunakake ing kode modern.
Generik kanggo kucing - 5

Kelas sing diketik

Dadi, kelas ngetik. Ayo ndeleng kepiye carane nulis kelas sing diketik dhewe. Contone, kita duwe hierarki kelas:
public static abstract class Animal {
  public abstract void voice();
}

public static class Cat extends Animal {
  public void voice(){
    System.out.println("Meow meow");
  }
}

public static class Dog extends Animal {
  public void voice(){
    System.out.println("Woof woof");
  }
}
Kita pengin nggawe kelas sing ngetrapake wadhah kewan. Bisa uga nulis kelas sing ngemot Animal. Iki prasaja, dingerteni, TAPI ... nyampur asu lan kucing iku ala, padha ora kekancan karo saben liyane. Kajaba iku, yen ana wong sing nampa wadhah kasebut, dheweke bisa uga salah mbuwang kucing saka wadhah menyang bungkus asu ... lan iki ora bakal nyebabake kabecikan. Lan ing kene generik bakal mbantu kita. Contone, ayo nulis implementasine kaya iki:
public static class Box<T> {
  List<T> slots = new ArrayList<>();
  public List<T> getSlots() {
    return slots;
  }
}
Kelas kita bakal nggarap obyek saka jinis sing ditemtokake dening generik sing jenenge T. Iki minangka jenis alias. Amarga Umum kasebut ditemtokake ing jeneng kelas, banjur kita bakal nampa nalika ngumumake kelas:
public static void main(String[] args) {
  Box<Cat> catBox = new Box<>();
  Cat murzik = new Cat();
  catBox.getSlots().add(murzik);
}
Minangka kita bisa ndeleng, kita nuduhake yen kita duwe Box, kang mung dianggo karo Cat. Compiler nyadari yen catBoxtinimbang generik, Tsampeyan kudu ngganti jinis Cating ngendi wae jeneng generik kasebut T:
Generik kanggo kucing - 6
Sing. iku thanks kanggo Box<Cat>compiler sing mangerténi apa slotssing kudu bener List<Cat>. Kanggo Box<Dog>nang bakal ana slots, ngemot List<Dog>. Ana sawetara generik ing deklarasi jinis, contone:
public static class Box<T, V> {
Jeneng umum bisa apa wae, sanajan dianjurake kanggo netepi sawetara aturan sing ora diucapake - "Konvensi Penamaan Parameter Tipe": Jinis unsur - E, jinis kunci - K, jinis nomer - N, T - kanggo jinis, V - kanggo jinis nilai . Miturut cara, elinga kita ngandika sing generik invariant, i.e. ora ngreksa hirarki pusaka. Ing kasunyatan, kita bisa mengaruhi iki. Sing, kita duwe kesempatan kanggo nggawe generik COvariant, i.e. tetep pusaka ing urutan padha. Prilaku iki diarani "Tipe Bounded", i.e. jinis winates. Contone, kelas kita Boxbisa ngemot kabeh kewan, banjur kita bakal ngumumake umum kaya iki:
public static class Box<T extends Animal> {
Sing, kita nyetel wates ndhuwur kanggo kelas Animal. Kita uga bisa nemtokake sawetara jinis sawise tembung kunci extends. Iki tegese jinis sing bakal kita lakoni kudu dadi turunan saka sawetara kelas lan ing wektu sing padha ngleksanakake sawetara antarmuka. Tuladhane:
public static class Box<T extends Animal & Comparable> {
Ing kasus iki, yen kita nyoba nglebokake Boxbarang sing dudu pewaris Animallan ora dileksanakake Comparable, banjur sajrone kompilasi kita bakal nampa kesalahan:
error: type argument Cat is not within bounds of type-variable T
Generik kanggo kucing - 7

Metode Ngetik

Generik digunakake ora mung ing jinis, nanging uga ing cara individu. Aplikasi metode kasebut bisa dideleng ing tutorial resmi: " Metode Generik ".

Latar mburi:

Generik kanggo kucing - 8
Ayo ndeleng gambar iki. Nalika sampeyan bisa ndeleng, compiler katon ing cara teken lan ndeleng sing kita njupuk sawetara kelas undefined minangka input. Iku ora nemtokake dening teken sing kita bali sawetara jenis obyek, i.e. obyek. Dadi, yen kita pengin nggawe, ucapake, ArrayList, mula kita kudu nindakake iki:
ArrayList<String> object = (ArrayList<String>) createObject(ArrayList.class);
Sampeyan kudu nulis kanthi jelas manawa output kasebut bakal dadi ArrayList, sing ala lan nambah kemungkinan kesalahan. Contone, kita bisa nulis omong kosong kasebut lan bakal dikompilasi:
ArrayList object = (ArrayList) createObject(LinkedList.class);
Apa kita bisa mbantu kompiler? Ya, generik ngidini kita nindakake iki. Ayo ndeleng conto sing padha:
Generik kanggo kucing - 9
Banjur, kita bisa nggawe obyek kaya iki:
ArrayList<String> object = createObject(ArrayList.class);
Generik kanggo kucing - 10

WildCard

Miturut Oracle's Tutorial on Generics, khusus bagean " Kartu liar ", kita bisa nggambarake "jinis sing ora dingerteni" kanthi tandha pitakon. Wildcard minangka alat sing migunani kanggo nyuda sawetara watesan generik. Contone, kaya sing wis kita rembugan sadurunge, generik iku invarian. Iki tegese sanajan kabeh kelas minangka turunan (subtipe) saka jinis Obyek, iku List<любой тип>dudu subtipe List<Object>. Nanging, List<любой тип>iku subtipe List<?>. Supaya kita bisa nulis kode ing ngisor iki:
public static void printList(List<?> list) {
  for (Object elem: list) {
    System.out.print(elem + " ");
  }
  System.out.println();
}
Kaya generik biasa (yaiku tanpa nggunakake wildcard), generik karo wildcard bisa diwatesi. Wildcard wates ndhuwur katon akrab:
public static void printCatList(List<? extends Cat> list) {
  for (Cat cat: list) {
    System.out.print(cat + " ");
  }
  System.out.println();
}
Nanging sampeyan uga bisa matesi kanthi wildcard Lower bound:
public static void printCatList(List<? super Cat> list) {
Mangkono, cara kasebut bakal miwiti nampa kabeh kucing, uga luwih dhuwur ing hirarki (nganti Obyek).
Generik kanggo kucing - 11

Tipe Erasure

Ngomong babagan generik, sampeyan kudu ngerti babagan "Jenis Busak". Nyatane, jinis erasure babagan kasunyatan manawa generik minangka informasi kanggo kompiler. Sajrone eksekusi program, ora ana informasi liyane babagan generik, iki diarani "mbusak". Pambusakan iki nduweni efek yen jinis generik diganti karo jinis tartamtu. Yen generik ora duwe wates, banjur jinis Obyek bakal diganti. Yen wates kasebut ditemtokake (contone <T extends Comparable>), banjur bakal diganti. Mangkene conto saka Tutorial Oracle: " Erasure of Generic Types ":
Generik kanggo kucing - 12
Kaya sing kasebut ing ndhuwur, ing conto iki generik Tdibusak menyang tapel watese, i.e. sadurunge Comparable.
Generik kanggo kucing - 13

Kesimpulan

Generik minangka topik sing menarik banget. Mugi topik iki menarik kanggo sampeyan. Kanggo ngringkes, kita bisa ngomong yen generik minangka alat sing apik sing ditampa pangembang kanggo njaluk kompiler kanthi informasi tambahan kanggo njamin keamanan jinis ing tangan siji lan keluwesan ing sisih liyane. Lan yen sampeyan kasengsem, aku saranake sampeyan mriksa sumber daya sing disenengi: #Viacheslav
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION