JavaRush /Blog Jawa /Random-JV /Teori generik ing basa Jawa utawa carane ngetrapake kurun...
Viacheslav
tingkat

Teori generik ing basa Jawa utawa carane ngetrapake kurung

Diterbitake ing grup

Pambuka

Diwiwiti karo JSE 5.0, generik ditambahake menyang arsenal basa Jawa.
Teori generik ing basa Jawa utawa cara ngleksanakake tanda kurung - 1

Apa generik ing basa Jawa?

Generik (generalisasi) minangka sarana khusus saka basa Jawa kanggo ngleksanakake pemrograman umum: pendekatan khusus kanggo njlentrehake data lan algoritma sing ngidini sampeyan nggarap macem-macem jinis data tanpa ngganti deskripsi. Ing situs web Oracle, tutorial kapisah khusus kanggo generik: " Pelajaran: Generik ".

Kaping pisanan, kanggo ngerti generik, sampeyan kudu ngerti sebabe kabeh dibutuhake lan apa sing diwenehake. Ing tutorial ing bagean " Napa Gunakake Generik ?" Disebutake manawa salah sawijining tujuan yaiku mriksa jinis wektu kompilasi sing luwih kuat lan ngilangi kabutuhan casting sing jelas.
Teori generik ing basa Jawa utawa cara ngetrapake tanda kurung - 2
Ayo nyiyapake kompiler java online tutorialspoint favorit kanggo eksperimen . Ayo mbayangno kode iki:
import java.util.*;
public class HelloWorld{
	public static void main(String []args){
		List list = new ArrayList();
		list.add("Hello");
		String text = list.get(0) + ", world!";
		System.out.print(text);
	}
}
Kode iki bakal mlaku kanthi apik. Nanging kepiye yen dheweke teka lan ujar manawa tembung kasebut "Halo, jagad!" diantemi lan sampeyan mung bisa bali Hello? Ayo mbusak concatenation karo senar saka kode ", world!". Iku bakal katon sing apa bisa luwih aman? Nanging nyatane, kita bakal nampa kesalahan sajrone KOMPILASI : error: incompatible types: Object cannot be converted to String Bab iku ing kasus kita List nyimpen dhaptar obyek saka jinis Obyek. Wiwit String minangka turunan saka Obyek (amarga kabeh kelas diwarisake sacara implisit saka Obyek ing Jawa), mbutuhake cast eksplisit, sing ora ditindakake. Lan nalika concatenating, cara statis String.valueOf (obj) bakal disebut ing obyek, kang wekasanipun bakal nelpon cara toString ing Obyek. Yaiku, Daftar kita ngemot Obyek. Pranyata yen kita butuh jinis tartamtu, lan dudu Obyek, kita kudu nindakake jinis casting dhewe:
import java.util.*;
public class HelloWorld{
	public static void main(String []args){
		List list = new ArrayList();
		list.add("Hello!");
		list.add(123);
		for (Object str : list) {
		    System.out.println((String)str);
		}
	}
}
Nanging, ing kasus iki, amarga List nampa dhaptar obyek, ora mung nyimpen String, nanging uga Integer. Nanging sing paling awon yaiku ing kasus iki, kompiler ora bakal weruh apa-apa sing salah. Lan ing kene kita bakal nampa kesalahan sajrone eksekusi (uga ujar manawa kesalahan kasebut ditampa "ing Runtime"). Kesalahan bakal dadi: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String Setuju, dudu sing paling nyenengake. Lan kabeh iki amarga compiler ora intelijen buatan lan ora bisa ngira kabeh sing dimaksud karo programmer. Kanggo ngandhani kompiler luwih akeh babagan jinis apa sing bakal digunakake, Java SE 5 ngenalake generik . Ayo mbenerake versi kita kanthi ngandhani kompiler apa sing dikarepake:
import java.util.*;
public class HelloWorld {
	public static void main(String []args){
		List<String> list = new ArrayList<>();
		list.add("Hello!");
		list.add(123);
		for (Object str : list) {
		    System.out.println(str);
		}
	}
}
Nalika kita bisa ndeleng, kita ora perlu maneh cast kanggo String. Kajaba iku, saiki kita duwe kurung sudut sing pigura generik. Saiki kompiler ora ngidini kelas dikompilasi nganti kita mbusak tambahan 123 menyang dhaptar, amarga iki Integer. Dheweke bakal ngandhani kita. Akeh wong nyebut generik "gula sintaksis". Lan padha bener, amarga generik pancen bakal dadi kasta sing padha nalika dikompilasi. Ayo ndeleng bytecode saka kelas sing dikompilasi: kanthi manual casting lan nggunakake generik:
Teori generik ing basa Jawa utawa cara ngetrapake tanda kurung - 3
Sawise kompilasi, informasi babagan generik bakal dibusak. Iki diarani "Tipe Erasure" utawa " Type Erasure ". Tipe erasure lan generik dirancang kanggo nyedhiyakake kompatibilitas mundur karo versi JDK sing luwih lawas, nalika isih ngidini kompiler mbantu inferensi jinis ing versi Jawa sing luwih anyar.
Teori generik ing basa Jawa utawa cara ngetrapake tanda kurung - 4

Jinis mentah utawa jinis mentah

Nalika ngomong babagan generik, kita mesthi duwe rong kategori: jinis diketik (Jenis Umum) lan jinis "mentah" (Tipe Raw). Jinis mentah minangka jinis tanpa nemtokake "kualifikasi" ing kurung sudut:
Teori generik ing basa Jawa utawa cara ngetrapake tanda kurung - 5
Jinis sing diketik yaiku kosok balene, kanthi indikasi "klarifikasi":
Teori generik ing basa Jawa utawa cara ngetrapake tanda kurung - 6
Kaya sing kita deleng, kita nggunakake desain sing ora biasa, ditandhani panah ing gambar. Iki minangka sintaks khusus sing ditambahake ing Java SE 7, lan diarani " berlian ", sing tegese berlian. Kenging punapa? Sampeyan bisa nggambar analogi antarane wangun berlian lan wangun kurung kriting: <> Sintaks Diamond uga digandhengake karo konsep " Ketik Inferensi ", utawa tipe inferensi. Sawise kabeh, kompiler, ndeleng <> ing sisih tengen, katon ing sisih kiwa, ing ngendi deklarasi jinis variabel sing ditugasake nilai kasebut. Lan saka bagean iki dheweke ngerti apa jinis nilai ing sisih tengen diketik. Nyatane, yen umum ditemtokake ing sisih kiwa lan ora ditemtokake ing sisih tengen, kompiler bakal bisa nyimpulake jinis kasebut:
import java.util.*;
public class HelloWorld{
	public static void main(String []args) {
		List<String> list = new ArrayList();
		list.add("Hello World");
		String data = list.get(0);
		System.out.println(data);
	}
}
Nanging, iki bakal dadi campuran gaya anyar karo generik lan gaya lawas tanpa. Lan iki arang banget undesirable. Nalika nyusun kode ing ndhuwur kita bakal nampa pesen: Note: HelloWorld.java uses unchecked or unsafe operations. Nyatane, ora jelas kenapa kita kudu nambah berlian ing kene. Nanging iki contone:
import java.util.*;
public class HelloWorld{
	public static void main(String []args) {
		List<String> list = Arrays.asList("Hello", "World");
		List<Integer> data = new ArrayList(list);
		Integer intNumber = data.get(0);
		System.out.println(data);
	}
}
Nalika kita ngelingi, ArrayList uga duwe konstruktor kapindho sing njupuk koleksi minangka input. Lan iki ngendi ngapusi dumunung. Tanpa sintaks berlian, kompiler ora ngerti yen diapusi, nanging kanthi inten. Mulane, aturan #1 : tansah nggunakake sintaks berlian yen kita nggunakake jinis diketik. Yen ora, kita risiko ilang ing ngendi kita nggunakake jinis mentah. Kanggo ngindhari bebaya ing log sing "nggunakake operasi sing ora dicenthang utawa ora aman" sampeyan bisa nemtokake anotasi khusus babagan metode utawa kelas sing digunakake: @SuppressWarnings("unchecked") Suppress diterjemahake minangka suppress, yaiku, kanthi harfiah, kanggo nyegah bebaya. Nanging pikirake kenapa sampeyan mutusake kanggo nuduhake? Elinga aturan nomer siji lan mungkin sampeyan kudu nambah ngetik.
Teori generik ing basa Jawa utawa carane ngetrapake kurung ing praktik - 7

Metode Umum

Generik ngidini sampeyan ngetik metode. Ana bagean kapisah khusus kanggo fitur iki ing tutorial Oracle: " Metode Umum ". Saka tutorial iki, penting kanggo ngelingi sintaksis:
  • kalebu dhaptar paramèter sing diketik ing jero kurung sudut;
  • dhaptar paramèter diketik dadi sadurunge cara bali.
Ayo katon ing conto:
import java.util.*;
public class HelloWorld{

    public static class Util {
        public static <T> T getValue(Object obj, Class<T> clazz) {
            return (T) obj;
        }
        public static <T> T getValue(Object obj) {
            return (T) obj;
        }
    }

    public static void main(String []args) {
		List list = Arrays.asList("Author", "Book");
		for (Object element : list) {
		    String data = Util.getValue(element, String.class);
		    System.out.println(data);
		    System.out.println(Util.<String>getValue(element));
		}
    }
}
Yen sampeyan ndeleng kelas Util, kita ndeleng rong cara sing diketik. Kanthi inferensi jinis, kita bisa menehi definisi jinis langsung menyang kompiler, utawa kita bisa nemtokake dhewe. Loro-lorone opsi diwenehi ing conto. Miturut cara, sintaks cukup logis yen sampeyan mikir babagan iki. Nalika ngetik metode, kita nemtokake generik sadurunge metode amarga yen kita nggunakake generik sawise metode, Jawa ora bakal bisa nemtokake jinis apa sing bakal digunakake. Mulane, kita pisanan ngumumake yen kita bakal nggunakake generik T, banjur kita ngomong yen kita bakal bali generik iki. Alami, Util.<Integer>getValue(element, String.class)bakal gagal kanthi kesalahan incompatible types: Class<String> cannot be converted to Class<Integer>. Nalika nggunakake cara diketik, sampeyan kudu tansah elinga bab erasure jinis. Ayo katon ing conto:
import java.util.*;
public class HelloWorld {

    public static class Util {
        public static <T> T getValue(Object obj) {
            return (T) obj;
        }
    }

    public static void main(String []args) {
		List list = Arrays.asList(2, 3);
		for (Object element : list) {
		    System.out.println(Util.<Integer>getValue(element) + 1);
		}
    }
}
Iku bakal bisa gedhe. Nanging mung anggere compiler mangertos yen cara disebut duwe jinis Integer. Ayo ngganti output console karo baris ing ngisor iki: System.out.println(Util.getValue(element) + 1); Lan kita entuk kesalahan: jinis operand ala kanggo operator binar '+', jinis pisanan: Obyek , jinis kapindho: int Yaiku, jinis wis dibusak. Compiler ndeleng manawa ora ana sing nemtokake jinis kasebut, jinis kasebut minangka Obyek lan eksekusi kode gagal kanthi kesalahan.
Teori generik ing basa Jawa utawa cara ngetrapake tanda kurung - 8

Jinis Umum

Sampeyan bisa ngetik ora mung cara, nanging uga kelas dhewe. Oracle duwe bagean " Jenis Umum " sing didedikake ing pandhuane. Ayo ndeleng conto:
public static class SomeType<T> {
	public <E> void test(Collection<E> collection) {
		for (E element : collection) {
			System.out.println(element);
		}
	}
	public void test(List<Integer> collection) {
		for (Integer element : collection) {
			System.out.println(element);
		}
	}
}
Kabeh iku prasaja ing kene. Yen kita nggunakake kelas, generik kadhaptar sawise jeneng kelas. Ayo saiki nggawe conto kelas iki ing metode utama:
public static void main(String []args) {
	SomeType<String> st = new SomeType<>();
	List<String> list = Arrays.asList("test");
	st.test(list);
}
Iku bakal bisa uga. Compiler weruh sing ana Dhaftar nomer lan Koleksi jinis String. Nanging apa yen kita mbusak generik lan nindakake iki:
SomeType st = new SomeType();
List<String> list = Arrays.asList("test");
st.test(list);
Kita bakal entuk kesalahan: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer Ketik erasure maneh. Wiwit kelas ora ana maneh generik, compiler mutusake yen wiwit kita ngliwati Daftar, metode karo List<Integer> luwih cocok. Lan kita tiba kanthi kesalahan. Mulane, aturan #2: Yen kelas diketik, mesthi nemtokake jinis ing generik .

Watesan

Kita bisa ngetrapake watesan kanggo jinis sing ditemtokake ing generik. Contone, kita pengin wadhah nampa mung Nomer minangka input. Fitur iki diterangake ing Tutorial Oracle ing bagean Parameter Tipe Wates . Ayo katon ing conto:
import java.util.*;
public class HelloWorld{

    public static class NumberContainer<T extends Number> {
        private T number;

        public NumberContainer(T number)  { this.number = number; }

        public void print() {
            System.out.println(number);
        }
    }

    public static void main(String []args) {
		NumberContainer number1 = new NumberContainer(2L);
		NumberContainer number2 = new NumberContainer(1);
		NumberContainer number3 = new NumberContainer("f");
    }
}
Kaya sing sampeyan ngerteni, kita wis mbatesi jinis umum dadi kelas nomer / antarmuka lan turunane. Apike, sampeyan bisa nemtokake ora mung kelas, nanging uga antarmuka. Contone: public static class NumberContainer<T extends Number & Comparable> { Generik uga duwe konsep Wildcard https://docs.oracle.com/javase/tutorial/java/generics/wildcards.html, banjur dipérang dadi telung jinis: Prinsip sing diarani Get Put ditrapake kanggo Wildcards . Padha bisa ditulis ing wangun ing ngisor iki:
Teori generik ing basa Jawa utawa cara ngetrapake tanda kurung - 9
Prinsip iki uga diarani prinsip PECS (Producer Extends Consumer Super). Sampeyan bisa maca liyane babagan Habré ing artikel " Nganggo wildcard umum kanggo nambah panggunaan API Java ", uga ing diskusi sing apik babagan stackoverflow: " Nggunakake wildcard ing Generics Java ". Iki conto cilik saka sumber Jawa - metode Collections.copy:
Teori generik ing basa Jawa utawa cara nglebokake tanda kurung ing laku - 10
Ya, conto cilik babagan carane ora bakal bisa:
public static class TestClass {
	public static void print(List<? extends String> list) {
		list.add("Hello World!");
		System.out.println(list.get(0));
	}
}

public static void main(String []args) {
	List<String> list = new ArrayList<>();
	TestClass.print(list);
}
Nanging yen sampeyan ngganti ngluwihi karo super, kabeh bakal nggoleki. Amarga kita ngisi dhaptar kanthi nilai sadurunge ngasilake, iku konsumen kanggo kita, yaiku konsumen. Mulane, kita nggunakake super.

pusaka

Ana fitur generik liyane sing ora biasa - warisane. Warisan generik diterangake ing tutorial Oracle ing bagean " Generik, Warisan, lan Subtipe ". Ingkang utama yaiku ngelingi lan nyadari ing ngisor iki. Kita ora bisa nindakake iki:
List<CharSequence> list1 = new ArrayList<String>();
Amarga warisan tumindak beda karo generik:
Teori generik ing basa Jawa utawa cara ngetrapake tanda kurung - 11
Lan iki conto liyane sing apik sing bakal gagal karo kesalahan:
List<String> list1 = new ArrayList<>();
List<Object> list2 = list1;
Kabeh uga prasaja ing kene. List<String> dudu turunan saka List<Object>, sanajan String minangka turunan saka Object.

Pungkasan

Dadi kita nyegerake memori babagan generik. Yen lagi arang digunakake ing kabeh daya, sawetara rincian tiba metu saka memori. Mugi review singkat iki mbantu refresh memori. Lan kanggo asil sing luwih gedhe, aku nyaranake sampeyan maca materi ing ngisor iki: #Viacheslav
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION