Yang kita tahu adalah " Semua instance dari kelas apa pun berbagi objek java.lang.Class yang sama dari jenis kelas "
misalnya)
Student a = new Student();
Student b = new Student();
Maka a.getClass() == b.getClass()
itu benar.
Sekarang anggaplah
Teacher t = new Teacher();
tanpa obat generik, di bawah ini dimungkinkan.
Class studentClassRef = t.getClass();
Tapi ini salah sekarang ..?
misalnya) public void printStudentClassInfo(Class studentClassRef) {}
dapat dipanggil denganTeacher.class
Ini bisa dihindari menggunakan obat generik.
Class<Student> studentClassRef = t.getClass(); //Compilation error.
Sekarang apa itu T ?? T adalah tipe parameter (juga disebut variabel tipe); dibatasi oleh kurung sudut (<>), mengikuti nama kelas.
T hanyalah simbol, seperti nama variabel (dapat berupa nama apa saja) yang dideklarasikan saat menulis file kelas. Nanti T itu akan diganti dengan
nama Kelas yang valid selama inisialisasi ( HashMap<String> map = new HashMap<String>();
)
misalnya) class name<T1, T2, ..., Tn>
Jadi Class<T>
mewakili objek kelas dari tipe kelas spesifik ' T
'.
Asumsikan bahwa metode kelas Anda harus bekerja dengan parameter tipe yang tidak dikenal seperti di bawah ini
/**
* Generic version of the Car class.
* @param <T> the type of the value
*/
public class Car<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Di sini T dapat digunakan sebagai String
tipe sebagai CarName
ATAU T dapat digunakan sebagai Integer
tipe sebagai modelNumber ,
ATAU T dapat digunakan sebagai Object
jenis sebagai instance mobil yang valid .
Sekarang di sini yang di atas adalah POJO sederhana yang dapat digunakan secara berbeda saat runtime.
Collections eg) List, Set, Hashmap adalah contoh terbaik yang akan bekerja dengan objek yang berbeda sesuai dengan deklarasi T, tetapi begitu kita mendeklarasikan T sebagai String
misalnya) HashMap<String> map = new HashMap<String>();
Maka ia hanya akan menerima objek instance String Class.
Metode Generik
Metode generik adalah metode yang memperkenalkan parameter tipe mereka sendiri. Ini mirip dengan mendeklarasikan tipe generik, tetapi lingkup parameter tipe terbatas pada metode yang dideklarasikan. Metode statis dan non-statis generik diperbolehkan, serta konstruktor kelas generik.
Sintaks untuk metode generik termasuk parameter tipe, kurung sudut dalam, dan muncul sebelum tipe pengembalian metode. Untuk metode generik, bagian parameter tipe harus muncul sebelum tipe pengembalian metode.
class Util {
// Generic static method
public static <K, V, Z, Y> boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
class Pair<K, V> {
private K key;
private V value;
}
Berikut <K, V, Z, Y>
ini adalah deklarasi jenis yang digunakan dalam argumen metode yang harus sebelum jenis kembali yang ada di boolean
sini.
Di bawah ini; deklarasi tipe <T>
tidak diperlukan pada level metode, karena sudah dideklarasikan di level kelas.
class MyClass<T> {
private T myMethod(T a){
return a;
}
}
Tetapi di bawah ini salah karena parameter tipe tingkat kelas K, V, Z, dan Y tidak dapat digunakan dalam konteks statis (metode statis di sini).
class Util <K, V, Z, Y>{
// Generic static method
public static boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
SKENARIO VALID LAINNYA ADALAH
class MyClass<T> {
//Type declaration <T> already done at class level
private T myMethod(T a){
return a;
}
//<T> is overriding the T declared at Class level;
//So There is no ClassCastException though a is not the type of T declared at MyClass<T>.
private <T> T myMethod1(Object a){
return (T) a;
}
//Runtime ClassCastException will be thrown if a is not the type T (MyClass<T>).
private T myMethod1(Object a){
return (T) a;
}
// No ClassCastException
// MyClass<String> obj= new MyClass<String>();
// obj.myMethod2(Integer.valueOf("1"));
// Since type T is redefined at this method level.
private <T> T myMethod2(T a){
return a;
}
// No ClassCastException for the below
// MyClass<String> o= new MyClass<String>();
// o.myMethod3(Integer.valueOf("1").getClass())
// Since <T> is undefined within this method;
// And MyClass<T> don't have impact here
private <T> T myMethod3(Class a){
return (T) a;
}
// ClassCastException for o.myMethod3(Integer.valueOf("1").getClass())
// Should be o.myMethod3(String.valueOf("1").getClass())
private T myMethod3(Class a){
return (T) a;
}
// Class<T> a :: a is Class object of type T
//<T> is overriding of class level type declaration;
private <T> Class<T> myMethod4(Class<T> a){
return a;
}
}
Dan akhirnya metode statis selalu membutuhkan <T>
deklarasi eksplisit ; Itu tidak akan berasal dari tingkat kelas Class<T>
. Ini karena level Kelas T terikat dengan instance.
Baca juga Pembatasan Generik
Wildcard dan Subtyping
ketik argumen untuk metode generik
Dari Dokumentasi Java:
[...] Lebih mengejutkan, kelas Kelas telah dibuat. Literal kelas sekarang berfungsi sebagai token tipe, menyediakan informasi tipe run-time dan compile-time. Ini memungkinkan gaya pabrik statis yang dicontohkan oleh metode getAnnotation di antarmuka AnnotatedElement yang baru:
Ini adalah metode generik. Itu menyimpulkan nilai parameter tipe T dari argumennya, dan mengembalikan instance T yang tepat, seperti yang diilustrasikan oleh cuplikan berikut:
Sebelum menggunakan obat generik, Anda harus menyerahkan hasilnya kepada Penulis. Anda juga tidak akan memiliki cara untuk membuat kompiler memeriksa bahwa parameter aktual mewakili subkelas Anotasi. [...]
Yah, saya tidak pernah harus menggunakan barang seperti ini. Siapa saja?
sumber
Class<? extends X>
notasi, saya pikir saya bisa membatasi hanya untuk tipe 'layanan'. Kecuali tidak ada tipe 'layanan' yang umum, jadi saya hanya bisa melakukannya denganClass<?>
. Sayang.Saya menemukan
class<T>
berguna ketika saya membuat layanan pencarian registri. Misalnyasumber
Seperti jawaban lain tunjukkan, ada banyak dan alasan bagus mengapa ini
class
dibuat generik. Namun ada banyak kali Anda tidak memiliki cara untuk mengetahui jenis generik yang akan digunakanClass<T>
. Dalam kasus ini, Anda bisa mengabaikan peringatan gerhana kuning atau Anda dapat menggunakanClass<?>
... Begitulah cara saya melakukannya;)sumber
@SuppressWarnings("unchecked")
datang untuk menyelamatkan! (Berhati-hatilah untuk selalu menerapkannya pada ruang lingkup sekecil mungkin karena hal itu mengaburkan masalah potensial dalam kode Anda.)Mengikuti jawaban @Kire Haglin, contoh lebih lanjut dari metode generik dapat dilihat dalam dokumentasi untuk JAXB unmarshalling :
Ini memungkinkan
unmarshal
untuk mengembalikan dokumen tipe pohon konten JAXB yang sewenang-wenang.sumber
Anda sering ingin menggunakan wildcard
Class
. Sebagai contoh,,Class<? extends JComponent>
akan memungkinkan Anda untuk menentukan bahwa kelas tersebut adalah beberapa subkelas dariJComponent
. Jika Anda telah mengambilClass
instance dariClass.forName
, maka Anda dapat menggunakanClass.asSubclass
untuk melakukan casting sebelum mencoba, katakanlah, membangun sebuah instance.sumber
Dalam java
<T>
berarti kelas Generik. Kelas Generik adalah kelas yang dapat bekerja pada semua jenis tipe data atau dengan kata lain kita dapat mengatakan itu adalah tipe data yang independen.Di mana T berarti tipe. Sekarang ketika Anda membuat instance dari kelas Shape ini, Anda perlu memberi tahu kompiler untuk tipe data apa yang akan dikerjakan.
Contoh:
Integer adalah tipe dan String juga tipe.
<T>
secara khusus singkatan dari tipe generik. Menurut Java Docs - Tipe generik adalah kelas generik atau antarmuka yang parameternya lebih dari tipe.sumber
Sebagai contoh lain, versi generik dari Class (
Class<T>
) memungkinkan seseorang untuk menulis fungsi-fungsi umum seperti yang di bawah ini.sumber
Ini membingungkan pada awalnya. Tetapi ini membantu dalam situasi di bawah ini:
sumber
Action a = new Action()
?Action
i an interface, ini adalahSomeAction
kami mencoba untuk mendapatkan contoh. Kami hanya memiliki nama yangSomeAction
tersedia saat runtime.Cukup gunakan kelas daging sapi:
sumber