Apa yang keren tentang obat generik, mengapa menggunakannya?


87

Saya pikir saya akan menawarkan softball ini kepada siapa pun yang ingin memukulnya keluar dari taman. Apa itu obat generik, apa kelebihan obat generik, mengapa, dimana, bagaimana cara menggunakannya? Harap pertahankan agar cukup mendasar. Terima kasih.


1
Duplikat stackoverflow.com/questions/77632/… . Tetapi jawaban sederhana, meskipun koleksi bukan bagian dari API Anda, saya tidak suka casting yang tidak perlu bahkan dalam implementasi internal.
Matthew Flaschen

Pertanyaannya sangat mirip, tetapi saya rasa jawaban yang diterima tidak menjawab pertanyaan ini.
Tom Hawtin - tackline


4
@MatthewFlaschen aneh, duplikat Anda langsung ke pertanyaan ini ... kesalahan dalam matriks!
jcollum

@jcollum, saya rasa pertanyaan asli yang saya kirimkan pada komentar itu telah digabungkan dengan pertanyaan ini.
Matthew Flaschen

Jawaban:


126
  • Memungkinkan Anda untuk menulis kode / menggunakan metode pustaka yang tipe-aman, yaitu Daftar <string> dijamin menjadi daftar string.
  • Sebagai hasil dari penggunaan generik, kompilator dapat melakukan pemeriksaan waktu kompilasi pada kode untuk keamanan tipe, misalnya apakah Anda mencoba memasukkan int ke dalam daftar string itu? Menggunakan ArrayList akan menyebabkan kesalahan waktu proses menjadi kurang transparan.
  • Lebih cepat daripada menggunakan objek karena ini menghindari boxing / unboxing (di mana .net harus mengubah tipe nilai menjadi tipe referensi atau sebaliknya ) atau mentransmisikan dari objek ke tipe referensi yang diperlukan.
  • Memungkinkan Anda untuk menulis kode yang dapat diterapkan ke banyak jenis dengan perilaku dasar yang sama, yaitu Dictionary <string, int> menggunakan kode dasar yang sama sebagai Dictionary <DateTime, double>; menggunakan obat generik, tim kerangka kerja hanya perlu menulis satu bagian kode untuk mencapai kedua hasil dengan keuntungan yang disebutkan di atas juga.

9
Ah, sangat bagus, dan saya suka daftar peluru. Saya rasa ini adalah jawaban yang paling lengkap namun ringkas sejauh ini.
MrBoJangles

seluruh penjelasannya ada dalam konteks "koleksi". Saya mencari tampilan yang lebih luas. ada pemikiran?
jungle_mole

jawaban yang bagus saya hanya ingin menambahkan 2 keuntungan lainnya, batasan umum memiliki 2 keuntungan di samping 1- Anda dapat menggunakan properti dari tipe terkendala dalam tipe umum (misalnya di mana T: IComparable menyediakan untuk menggunakan CompareTo) 2- Orang yang akan menulis kode setelah Anda akan tahu apa yang akan dilakukan
Hamit YILDIRIM

52

Saya benar-benar benci untuk mengulang. Saya benci mengetik hal yang sama lebih sering daripada yang seharusnya. Saya tidak suka mengulang beberapa kali dengan sedikit perbedaan.

Daripada membuat:

class MyObjectList  {
   MyObject get(int index) {...}
}
class MyOtherObjectList  {
   MyOtherObject get(int index) {...}
}
class AnotherObjectList  {
   AnotherObject get(int index) {...}
}

Saya dapat membuat satu kelas yang dapat digunakan kembali ... (dalam kasus di mana Anda tidak ingin menggunakan koleksi mentah karena suatu alasan)

class MyList<T> {
   T get(int index) { ... }
}

Saya sekarang 3x lebih efisien dan saya hanya perlu menyimpan satu salinan. Mengapa Anda TIDAK ingin mempertahankan lebih sedikit kode?

Ini juga berlaku untuk kelas non-koleksi seperti a Callable<T>atau Reference<T>yang harus berinteraksi dengan kelas lain. Apakah Anda benar-benar ingin memperluas Callable<T>dan Future<T>dan setiap kelas terkait lainnya untuk membuat versi yang aman bagi tipe?

Bukan saya.


1
Saya tidak yakin saya mengerti. Saya tidak menyarankan Anda membuat pembungkus "MyObject", itu akan mengerikan. Saya menyarankan jika koleksi objek Anda adalah koleksi Mobil, maka Anda menulis objek Garage. Itu tidak akan mendapatkan (mobil), itu akan memiliki metode seperti buyFuel (100) yang akan membeli bahan bakar $ 100 dan mendistribusikannya di antara mobil-mobil yang paling membutuhkannya. Saya berbicara tentang kelas bisnis nyata, bukan hanya "pembungkus". Misalnya, Anda hampir tidak pernah mendapatkan (mobil) atau mengulanginya di luar koleksi - Anda tidak meminta Objek untuk anggotanya, melainkan Anda memintanya untuk melakukan operasi untuk Anda.
Bill K

Bahkan di dalam garasi Anda, Anda harus memiliki keamanan tipe. Jadi, Anda memiliki List <Cars>, ListOfCars atau Anda melakukan cast di mana-mana. Saya tidak merasa perlu untuk menyatakan tipe lebih dari waktu minimum yang diperlukan.
James Schek

Saya setuju bahwa jenis keamanan akan menyenangkan, tetapi itu jauh lebih tidak membantu karena terbatas pada kelas garasi. Ini dikemas dan mudah dikontrol, jadi maksud saya adalah memberi Anda sedikit keuntungan ini dengan biaya sintaks baru. Ini seperti memodifikasi konstitusi AS untuk membuat menjalankan lampu merah ilegal - Ya, itu harus selalu ilegal tetapi apakah itu membenarkan amandemen? Saya juga berpikir ini mendorong orang untuk TIDAK menggunakan enkapsulasi untuk kasus ini, yang sebenarnya relatif berbahaya.
Bill K

Bill - Anda mungkin ada benarnya tentang tidak-menggunakan-enkapsulasi, tetapi argumen Anda lainnya adalah perbandingan yang buruk. Biaya mempelajari sintaks baru dalam kasus ini minimal (bandingkan dengan lambda di C #); membandingkan ini dengan amandemen Konstitusi tidak masuk akal. Konstitusi tidak bermaksud untuk menentukan kode lalu lintas. Ini lebih seperti beralih ke versi cetak Serif-Font di papan poster daripada salinan tulisan tangan di perkamen. Artinya sama, tetapi jauh lebih jelas dan lebih mudah dibaca.
James Schek

Contoh membuat konsep lebih praktis. Terima kasih untuk itu.
RayLoveless

22

Tidak perlu typecast adalah salah satu keuntungan terbesar dari generik Java , karena ia akan melakukan pemeriksaan jenis pada waktu kompilasi. Ini akan mengurangi kemungkinanClassCastException yang dapat dilemparkan saat runtime, dan dapat menghasilkan kode yang lebih kuat.

Tetapi saya curiga Anda sepenuhnya menyadarinya.

Setiap kali saya melihat Generik, itu membuat saya pusing. Saya menemukan bagian terbaik dari Java adalah kesederhanaannya dan sintaksis minimal dan generik tidak sederhana dan menambahkan sejumlah besar sintaks baru.

Pada awalnya, saya juga tidak melihat manfaat obat generik. Saya mulai belajar Java dari sintaks 1.4 (meskipun Java 5 keluar pada saat itu) dan ketika saya menemukan generik, saya merasa lebih banyak kode untuk ditulis, dan saya benar-benar tidak mengerti manfaatnya.

IDE modern membuat penulisan kode dengan generik lebih mudah.

IDE yang paling modern dan layak cukup pintar untuk membantu menulis kode dengan obat generik, terutama dengan penyelesaian kode.

Berikut contoh pembuatan Map<String, Integer>dengan a HashMap. Kode yang harus saya ketik adalah:

Map<String, Integer> m = new HashMap<String, Integer>();

Dan memang, banyak sekali mengetik hanya untuk membuat yang baru HashMap. Namun, pada kenyataannya, saya hanya perlu mengetik sebanyak ini sebelum Eclipse tahu apa yang saya butuhkan:

Map<String, Integer> m = new Ha Ctrl+Space

Benar, saya memang perlu memilih HashMapdari daftar kandidat, tetapi pada dasarnya IDE tahu apa yang harus ditambahkan, termasuk tipe generik. Dengan alat yang tepat, menggunakan obat generik tidak terlalu buruk.

Selain itu, karena jenisnya diketahui, saat mengambil elemen dari koleksi generik, IDE akan bertindak seolah-olah objek tersebut sudah menjadi objek dari jenis yang dideklarasikan - tidak perlu melakukan casting agar IDE mengetahui jenis objek tersebut. adalah.

Keuntungan utama dari obat generik berasal dari cara kerjanya yang baik dengan fitur Java 5 yang baru. Berikut adalah contoh melempar bilangan bulat ke a Setdan menghitung totalnya:

Set<Integer> set = new HashSet<Integer>();
set.add(10);
set.add(42);

int total = 0;
for (int i : set) {
  total += i;
}

Dalam potongan kode itu, ada tiga fitur Java 5 baru yang ada:

Pertama, generik dan autoboxing primitif memungkinkan baris berikut:

set.add(10);
set.add(42);

Integer di 10-autobox menjadi sebuah Integerdengan nilai 10. (Dan sama untuk 42). Kemudian yang Integerdilemparkan ke dalam Setyang dikenal dengan Integers. Mencoba memasukkan Stringakan menyebabkan kesalahan kompilasi.

Selanjutnya, for-each loop mengambil ketiga dari itu:

for (int i : set) {
  total += i;
}

Pertama, s yang Setberisi Integerdigunakan dalam for-each loop. Setiap elemen dideklarasikan sebagai sebuah intdan yang diizinkan saat Integerdikembalikan ke kotak primitif int. Dan fakta bahwa unboxing ini terjadi diketahui karena obat generik digunakan untuk menentukan bahwa ada yang Integerdisimpan di fileSet .

Generik bisa menjadi perekat yang menyatukan fitur-fitur baru yang diperkenalkan di Java 5, dan itu membuat pengkodean lebih sederhana dan lebih aman. Dan sebagian besar waktu IDE cukup pintar untuk membantu Anda dengan saran yang bagus, jadi umumnya, itu tidak akan lebih banyak mengetik.

Dan terus terang, seperti yang bisa dilihat dari Set contoh, saya merasa bahwa memanfaatkan fitur Java 5 dapat membuat kode lebih ringkas dan kuat.

Edit - Contoh tanpa obat generik

Berikut adalah ilustrasi Setcontoh di atas tanpa menggunakan obat generik. Itu mungkin, tetapi tidak terlalu menyenangkan:

Set set = new HashSet();
set.add(10);
set.add(42);

int total = 0;
for (Object o : set) {
  total += (Integer)o;
}

(Catatan: Kode di atas akan menghasilkan peringatan konversi yang tidak dicentang pada waktu kompilasi.)

Saat menggunakan koleksi non-generik, tipe yang dimasukkan ke dalam koleksi adalah tipe objek Object. Oleh karena itu, dalam contoh ini, a Objectadalah apa yang sedang adddiedit ke dalam himpunan.

set.add(10);
set.add(42);

Di baris di atas, autoboxing dalam bermain - primitif intnilai 10dan 42sedang autoboxed menjadi Integerobjek, yang sedang ditambahkan ke Set. Namun, perlu diingat, Integerobjek ditangani sebagai Objects, karena tidak ada informasi tipe untuk membantu kompilator mengetahui tipe apa yang Setdiharapkan.

for (Object o : set) {

Ini adalah bagian yang sangat penting. Alasan for-each loop berfungsi adalah karena antarmuka Setmengimplementasikan Iterable, yang mengembalikan Iteratorinformasi with type, jika ada. (Iterator<T> , itu.)

Namun, karena tidak ada informasi tipe, Setkehendak mengembalikan Iteratoryang akan mengembalikan nilai dalam Setas Objects, dan itulah mengapa elemen yang diambil di untuk-setiap loop harus berjenisObject .

Sekarang setelah Objectdiambil dari Set, itu perlu dilemparkan ke Integermanual untuk melakukan penambahan:

  total += (Integer)o;

Di sini, typecast dilakukan dari sebuah Objectke Integer. Dalam hal ini, kami tahu ini akan selalu berfungsi, tetapi typecasting manual selalu membuat saya merasa ini adalah kode yang rapuh yang dapat rusak jika perubahan kecil dilakukan di tempat lain. (Saya merasa bahwa setiap typecast ClassCastExceptionmenunggu untuk terjadi, tetapi saya ngelantur ...)

The Integerkini unboxed menjadi intdan memungkinkan untuk melakukan penambahan ke dalam intvariabel total.

Saya harap saya dapat mengilustrasikan bahwa fitur baru Java 5 dapat digunakan dengan kode non-generik, tetapi tidak sebersih dan langsung menulis kode dengan obat generik. Dan, menurut pendapat saya, untuk memanfaatkan sepenuhnya fitur-fitur baru di Java 5, kita harus melihat ke generik, jika paling tidak, memungkinkan pemeriksaan waktu kompilasi untuk mencegah typecast yang tidak valid membuang pengecualian saat runtime.


Integrasi dengan loop for yang ditingkatkan sangat bagus (meskipun saya pikir loop sialan itu rusak karena saya tidak dapat menggunakan sintaks yang sama persis dengan koleksi non-generik - seharusnya hanya menggunakan cast / autobox ke int, itu didapat semua informasi yang diperlukan!), tetapi Anda benar, bantuan di IDE mungkin bagus. Saya masih tidak tahu apakah itu cukup untuk membenarkan sintaks tambahan, tetapi setidaknya itu adalah sesuatu yang dapat saya manfaatkan (yang menjawab pertanyaan saya).
Bill K

@Bill K: Saya telah menambahkan contoh penggunaan fitur Java 5 tanpa menggunakan generik.
coobird

Itu adalah poin yang bagus, saya belum pernah menggunakannya (saya sebutkan saya telah terjebak, pada 1.4 dan lebih awal selama bertahun-tahun sekarang). Saya setuju bahwa ada keuntungan, tetapi kesimpulan yang saya capai adalah A) mereka cenderung cukup menguntungkan bagi orang yang tidak menggunakan OO dengan benar dan kurang berguna bagi mereka yang melakukannya, dan B) Keuntungan Anda ' telah terdaftar adalah keuntungan, tetapi hampir tidak cukup layak untuk membenarkan bahkan perubahan sintaks kecil, apalagi perubahan besar yang diperlukan untuk benar-benar grok generik seperti yang diterapkan di Java. Tapi setidaknya ada keuntungannya.
Bill K

15

Jika Anda mencari database bug Java sebelum 1.5 dirilis, Anda akan menemukan tujuh kali lebih banyak bug dengan NullPointerExceptionthan ClassCastException. Jadi sepertinya bukan fitur yang bagus untuk menemukan bug, atau setidaknya bug yang tetap ada setelah sedikit pengujian asap.

Bagi saya, keuntungan besar dari obat generik adalah bahwa mereka mendokumentasikan informasi jenis kode yang penting. Jika saya tidak ingin informasi jenis itu didokumentasikan dalam kode, maka saya akan menggunakan bahasa yang diketik secara dinamis, atau setidaknya bahasa dengan jenis inferensi yang lebih implisit.

Menyimpan koleksi objek untuk dirinya sendiri bukanlah gaya yang buruk (tetapi gaya yang umum adalah mengabaikan enkapsulasi secara efektif). Ini lebih tergantung pada apa yang Anda lakukan. Meneruskan koleksi ke "algoritme" sedikit lebih mudah untuk diperiksa (pada atau sebelum waktu kompilasi) dengan obat generik.


6
Tidak hanya itu didokumentasikan (yang dengan sendirinya merupakan kemenangan besar), itu diberlakukan oleh compiler.
James Schek

Poin bagus, tapi bukankah itu juga dicapai dengan melampirkan koleksi dalam kelas yang mendefinisikan "kumpulan objek jenis ini"?
Bill K

1
James: Ya, itulah intinya didokumentasikan dalam kode .
Tom Hawtin - tackline

Saya rasa saya tidak tahu perpustakaan bagus yang menggunakan koleksi untuk "Algoritma" (mungkin menyiratkan bahwa Anda berbicara tentang "Fungsi" yang membuat saya percaya bahwa mereka harus menjadi metode dalam objek koleksi). Saya pikir JDK hampir selalu mengekstrak array yang bagus dan bersih yang merupakan salinan data sehingga tidak dapat dikacaukan - setidaknya lebih sering daripada tidak.
Bill K

Juga, bukankah memiliki objek yang menjelaskan dengan tepat bagaimana koleksi digunakan dan membatasinya menggunakan bentuk dokumentasi dalam kode yang JAUH lebih baik? Saya menemukan informasi yang diberikan dalam obat generik sangat berlebihan dalam kode yang baik.
Bill K

11

Generik di Java memfasilitasi polimorfisme parametrik . Melalui parameter tipe, Anda bisa meneruskan argumen ke tipe. Sama seperti metode seperti String foo(String s)memodelkan beberapa perilaku, tidak hanya untuk string tertentu, tetapi untuk string apa pun s, jadi tipe seperti List<T>memodelkan beberapa perilaku, tidak hanya untuk jenis tertentu, tetapi untuk jenis apa pun . List<T>mengatakan bahwa untuk semua tipe T, ada tipe Listyang elemennya adalah Ts . Jadi Listsebenarnya adalah tipe konstruktor . Ini mengambil tipe sebagai argumen dan membangun tipe lain sebagai hasilnya.

Berikut adalah beberapa contoh tipe generik yang saya gunakan setiap hari. Pertama, antarmuka umum yang sangat berguna:

public interface F<A, B> {
  public B f(A a);
}

Antarmuka ini mengatakan bahwa untuk dua jenis, Adan B, ada fungsi (disebut f) yang mengambil Adan mengembalikan a B. Saat Anda mengimplementasikan antarmuka ini, Adan Bbisa jenis apa pun yang Anda inginkan, selama Anda menyediakan fungsi fyang mengambil yang pertama dan mengembalikan yang terakhir. Berikut contoh implementasi antarmuka:

F<Integer, String> intToString = new F<Integer, String>() {
  public String f(int i) {
    return String.valueOf(i);
  }
}

Sebelum generik, polimorfisme dicapai dengan subclassing menggunakan extendskata kunci. Dengan obat generik, kita sebenarnya bisa menghilangkan subclass dan menggunakan polimorfisme parametrik sebagai gantinya. Misalnya, pertimbangkan kelas berparameterisasi (generik) yang digunakan untuk menghitung kode hash untuk semua jenis. Alih-alih menimpa Object.hashCode (), kita akan menggunakan kelas generik seperti ini:

public final class Hash<A> {
  private final F<A, Integer> hashFunction;

  public Hash(final F<A, Integer> f) {
    this.hashFunction = f;
  }

  public int hash(A a) {
    return hashFunction.f(a);
  }
}

Ini jauh lebih fleksibel daripada menggunakan pewarisan, karena kita bisa tetap menggunakan tema penggunaan komposisi dan polimorfisme parametrik tanpa mengunci hierarki yang rapuh.

Generik Java tidak sempurna. Anda bisa mengabstraksi tipe, tetapi Anda tidak bisa mengabstraksi konstruktor tipe, misalnya. Artinya, Anda dapat mengatakan "untuk semua tipe T", tetapi Anda tidak dapat mengatakan "untuk tipe T apa pun yang menggunakan parameter tipe A".

Saya menulis artikel tentang batasan generik Java ini, di sini.

Satu keuntungan besar dengan obat generik adalah mereka memungkinkan Anda menghindari subclass. Subclassing cenderung menghasilkan hierarki kelas yang rapuh yang canggung untuk diperluas, dan kelas yang sulit dipahami secara individual tanpa melihat seluruh hierarki.

Wereas sebelum generik Anda mungkin memiliki kelas seperti Widgetdiperpanjang oleh FooWidget, BarWidget, dan BazWidget, dengan obat generik Anda bisa memiliki kelas generik tunggal Widget<A>yang membutuhkan Foo, Baratau Bazdalam konstruktor untuk memberikan Widget<Foo>, Widget<Bar>dan Widget<Baz>.


Ini akan menjadi poin yang bagus tentang subclass jika Java tidak memiliki antarmuka. Bukankah benar jika FooWidget, BarWidtet dan BazWidget semuanya menerapkan Widget? Saya bisa saja salah tentang hal ini .. Tapi ini adalah poin yang sangat bagus jika saya salah.
Bill K.

Mengapa Anda memerlukan kelas generik dinamis untuk menghitung nilai hash? Bukankah fungsi statis dengan parameter yang sesuai untuk pekerjaan lebih efisien?
Ant_222

8

Generik menghindari pukulan kinerja tinju dan unboxing. Pada dasarnya, lihat ArrayList vs List <T>. Keduanya melakukan hal inti yang sama, tetapi List <T> akan jauh lebih cepat karena Anda tidak perlu melakukan box ke / dari objek.


Itulah intinya, bukan? Bagus.
MrBoJangles

Tidak seluruhnya; mereka berguna untuk keamanan tipe + menghindari gips untuk tipe referensi juga tanpa memasukkan tinju / unboxing sama sekali.
ljs

Jadi saya kira pertanyaan berikut ini adalah, "Mengapa saya harus menggunakan ArrayList?" Dan, membahayakan jawaban, saya akan mengatakan bahwa ArrayLists baik-baik saja selama Anda tidak berharap untuk mengemas dan membuka kotak nilai mereka banyak. Komentar?
MrBoJangles

Tidak, mereka sudah tidak berfungsi sejak .net 2; hanya berguna untuk kompatibilitas mundur. ArrayLists lebih lambat, tidak aman untuk mengetik dan membutuhkan tinju / unboxing atau casting.
ljs

Jika Anda tidak menyimpan tipe nilai (misalnya ints atau struct), tidak ada tinju saat menggunakan ArrayList - kelas sudah menjadi 'objek'. Menggunakan List <T> masih jauh lebih baik karena jenis keamanannya, dan jika Anda benar-benar ingin menyimpan objek, lebih baik menggunakan List <object>.
Wilka

6

Manfaat terbaik untuk Generics adalah penggunaan kembali kode. Katakanlah Anda memiliki banyak objek bisnis, dan Anda akan menulis kode yang SANGAT mirip untuk setiap entitas untuk melakukan tindakan yang sama. (IE Linq ke operasi SQL).

Dengan generik, Anda dapat membuat kelas yang akan dapat beroperasi dengan jenis apa pun yang mewarisi dari kelas dasar tertentu atau mengimplementasikan antarmuka yang diberikan seperti:

public interface IEntity
{

}

public class Employee : IEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int EmployeeID { get; set; }
}

public class Company : IEntity
{
    public string Name { get; set; }
    public string TaxID { get; set }
}

public class DataService<ENTITY, DATACONTEXT>
    where ENTITY : class, IEntity, new()
    where DATACONTEXT : DataContext, new()
{

    public void Create(List<ENTITY> entities)
    {
        using (DATACONTEXT db = new DATACONTEXT())
        {
            Table<ENTITY> table = db.GetTable<ENTITY>();

            foreach (ENTITY entity in entities)
                table.InsertOnSubmit (entity);

            db.SubmitChanges();
        }
    }
}

public class MyTest
{
    public void DoSomething()
    {
        var dataService = new DataService<Employee, MyDataContext>();
        dataService.Create(new Employee { FirstName = "Bob", LastName = "Smith", EmployeeID = 5 });
        var otherDataService = new DataService<Company, MyDataContext>();
            otherDataService.Create(new Company { Name = "ACME", TaxID = "123-111-2233" });

    }
}

Perhatikan penggunaan kembali layanan yang sama dengan jenis yang berbeda dalam metode DoSomething di atas. Benar-benar elegan!

Ada banyak alasan bagus lainnya untuk menggunakan obat generik untuk pekerjaan Anda, ini adalah favorit saya.


5

Saya suka mereka karena mereka memberi Anda cara cepat untuk menentukan jenis kustom (seperti yang saya gunakan).

Jadi misalnya, alih-alih mendefinisikan struktur yang terdiri dari string dan integer, lalu harus mengimplementasikan seluruh kumpulan objek dan metode tentang cara mengakses array dari struktur tersebut dan seterusnya, Anda cukup membuat Dictionary

Dictionary<int, string> dictionary = new Dictionary<int, string>();

Dan compiler / IDE melakukan tugas berat lainnya. Kamus khususnya memungkinkan Anda menggunakan tipe pertama sebagai kunci (tidak ada nilai yang berulang).


5
  • Koleksi yang diketik - bahkan jika Anda tidak ingin menggunakannya, kemungkinan besar Anda harus menanganinya dari perpustakaan lain, sumber lain.

  • Pengetikan umum dalam pembuatan kelas:

    kelas publik Foo <T> {publik T get () ...

  • Menghindari casting - Saya selalu tidak menyukai hal-hal seperti

    Pembanding baru {public int bandingkanTo (Object o) {if (o instanceof classIcareAbout) ...

Di mana Anda pada dasarnya memeriksa kondisi yang seharusnya hanya ada karena antarmuka diekspresikan dalam bentuk objek.

Reaksi awal saya terhadap obat generik mirip dengan Anda - "terlalu berantakan, terlalu rumit". Pengalaman saya adalah bahwa setelah menggunakannya sebentar Anda akan terbiasa dengan mereka, dan kode tanpa mereka terasa kurang jelas ditentukan, dan hanya kurang nyaman. Selain itu, seluruh dunia java menggunakannya sehingga Anda harus mengikuti program pada akhirnya, bukan?


1
agar akurat mengenai penghindaran casting: casting terjadi, menurut dokumentasi Sun, tetapi dilakukan oleh compiler. Anda hanya bisa menghindari menulis gips dalam kode Anda.
Demi

Mungkin, saya tampaknya terjebak dalam rangkaian panjang perusahaan yang tidak mau naik di atas 1,4, jadi siapa tahu, saya mungkin pensiun sebelum saya mencapai 5. Belakangan ini saya juga berpikir bahwa membagi "SimpleJava" mungkin merupakan konsep yang menarik --Java akan terus menambahkan fitur dan untuk banyak kode yang pernah saya lihat, itu tidak akan menjadi hal yang sehat. Saya sudah berurusan dengan orang-orang yang tidak bisa membuat kode loop - saya benci melihat mereka mencoba memasukkan obat generik ke dalam loop mereka yang tidak digulung tanpa tujuan.
Bill K

@Bill K: Hanya sedikit orang yang perlu menggunakan kekuatan penuh obat generik. Itu hanya diperlukan saat Anda menulis kelas yang itu sendiri generik.
Eddie

5

Memberi contoh yang baik. Bayangkan Anda memiliki kelas bernama Foo

public class Foo
{
   public string Bar() { return "Bar"; }
}

Contoh 1 Sekarang Anda ingin memiliki koleksi objek Foo. Anda memiliki dua opsi, LIst atau ArrayList, keduanya bekerja dengan cara yang sama.

Arraylist al = new ArrayList();
List<Foo> fl = new List<Foo>();

//code to add Foos
al.Add(new Foo());
f1.Add(new Foo());

Dalam kode di atas, jika saya mencoba menambahkan kelas FireTruck alih-alih Foo, ArrayList akan menambahkannya, tetapi Daftar Generik Foo akan menyebabkan pengecualian untuk dilempar.

Contoh dua.

Sekarang Anda memiliki dua daftar array dan Anda ingin memanggil fungsi Bar () pada masing-masing. Karena hte ArrayList diisi dengan Objek, Anda harus membuangnya sebelum Anda dapat memanggil bilah. Tetapi karena Daftar Umum Foo hanya dapat berisi Foo, Anda dapat memanggil Bar () langsung pada Foo tersebut.

foreach(object o in al)
{
    Foo f = (Foo)o;
    f.Bar();
}

foreach(Foo f in fl)
{
   f.Bar();
}

Saya menduga Anda menjawab sebelum membaca pertanyaan. Itu adalah dua kasus yang tidak banyak membantu saya (dijelaskan dalam pertanyaan). Apakah ada kasus lain di mana ia melakukan sesuatu yang berguna?
Bill K

4

Pernahkah Anda menulis metode (atau kelas) di mana konsep kunci dari metode / kelas tidak terikat erat dengan tipe data tertentu dari parameter / variabel contoh (pikirkan daftar tertaut, fungsi maks / menit, pencarian biner , dll.).

Pernahkah Anda berharap dapat menggunakan kembali algorthm / kode tanpa menggunakan cut-n-paste reuse atau mengorbankan pengetikan yang kuat (misalnya saya ingin salah satu Listdari Strings, bukan salah Listsatu hal yang saya harap adalah string!)?

Itulah mengapa Anda harus ingin menggunakan obat generik (atau sesuatu yang lebih baik).


Saya tidak pernah harus menyalin / menempelkan kembali untuk hal semacam ini (Tidak yakin bagaimana itu akan terjadi?) Anda menerapkan antarmuka yang sesuai dengan kebutuhan Anda, dan menggunakan antarmuka itu. Kasus langka di mana Anda tidak dapat melakukan ini adalah ketika Anda menulis utilitas murni (seperti koleksi), dan untuk itu (seperti yang saya jelaskan dalam pertanyaan) itu benar-benar tidak pernah menjadi masalah. Saya berkompromi dengan pengetikan yang kuat - Sama seperti yang Anda lakukan jika menggunakan refleksi. Apakah Anda benar-benar menolak untuk menggunakan refleksi karena Anda tidak bisa mengetik yang kuat? (Jika saya harus menggunakan refleksi, saya hanya merangkumnya seperti koleksi).
Bill K

3

Jangan lupa bahwa obat generik tidak hanya digunakan oleh kelas, tetapi juga dapat digunakan oleh metode. Misalnya, ambil cuplikan berikut:

private <T extends Throwable> T logAndReturn(T t) {
    logThrowable(t); // some logging method that takes a Throwable
    return t;
}

Ini sederhana, tetapi bisa digunakan dengan sangat elegan. Hal yang menyenangkan adalah bahwa metode ini mengembalikan apa pun yang diberikan. Ini membantu saat Anda menangani pengecualian yang perlu dikembalikan ke pemanggil:

    ...
} catch (MyException e) {
    throw logAndReturn(e);
}

Intinya adalah Anda tidak kehilangan tipe dengan meneruskannya melalui suatu metode. Anda dapat menampilkan jenis pengecualian yang benar, bukan hanya a Throwable, yang bisa Anda lakukan tanpa obat generik.

Ini hanyalah contoh sederhana dari satu penggunaan untuk metode umum. Ada beberapa hal rapi lainnya yang dapat Anda lakukan dengan metode umum. Yang paling keren, menurut saya, adalah tipe menyimpulkan dengan obat generik. Ambil contoh berikut (diambil dari Josh Bloch's Effective Java 2nd Edition):

...
Map<String, Integer> myMap = createHashMap();
...
public <K, V> Map<K, V> createHashMap() {
    return new HashMap<K, V>();
}

Ini tidak banyak membantu, tetapi mengurangi beberapa kekacauan ketika tipe generiknya panjang (atau bersarang; yaitu Map<String, List<String>>).


Saya tidak berpikir itu benar tentang pengecualian. Itu membuat saya berpikir, tetapi saya 95% yakin Anda akan mendapatkan hasil yang persis sama tanpa menggunakan obat generik sama sekali (dan kode yang lebih jelas). Jenis informasi adalah bagian dari objek, bukan apa yang Anda transmisikan. Saya tergoda untuk mencobanya - mungkin besok saya akan bekerja dan kembali kepada Anda .. Begini saja, saya akan mencobanya dan jika Anda benar, saya akan melakukannya daftar posting Anda dan pilih 5 posting Anda :) Jika tidak, Anda mungkin ingin mempertimbangkan bahwa ketersediaan sederhana dari obat generik telah menyebabkan Anda mempersulit kode Anda tanpa keuntungan.
Bill K

Memang benar ini menambah kerumitan ekstra. Namun, saya pikir itu ada gunanya. Masalahnya adalah Anda tidak dapat membuang metode lama Throwabledari dalam tubuh metode yang memiliki pengecualian khusus yang dinyatakan. Alternatifnya adalah menulis metode terpisah untuk mengembalikan setiap jenis pengecualian, atau melakukan transmisi sendiri dengan metode non-umum yang mengembalikan file Throwable. Yang pertama terlalu bertele-tele dan sangat tidak berguna dan yang terakhir tidak akan mendapatkan bantuan dari kompiler. Dengan menggunakan obat generik, kompiler akan secara otomatis memasukkan cast yang benar untuk Anda. Jadi, pertanyaannya adalah: apakah itu sebanding dengan kerumitannya?
jigawot

Oh, saya mengerti. Jadi itu menghindari pemeran yang keluar ... poin yang bagus. Aku berhutang budi padamu 5.
Bill K

2

Keuntungan utama, seperti yang ditunjukkan Mitchel, adalah pengetikan yang kuat tanpa perlu mendefinisikan banyak kelas.

Dengan cara ini Anda dapat melakukan hal-hal seperti:

List<SomeCustomClass> blah = new List<SomeCustomClass>();
blah[0].SomeCustomFunction();

Tanpa obat generik, Anda harus mentransmisikan bla [0] ke jenis yang benar untuk mengakses fungsinya.


Diberikan pilihan, saya lebih suka tidak melakukan cast daripada cast.
MrBoJangles

Pengetikan yang kuat dengan mudah merupakan aspek terbaik dari imho generik, terutama mengingat pemeriksaan jenis waktu kompilasi yang memungkinkan.
ljs

2

jvm tetap melakukan cast ... ia secara implisit membuat kode yang memperlakukan tipe generik sebagai "Object" dan membuat cast ke instance yang diinginkan. Generik Java hanyalah gula sintaksis.


2

Saya tahu ini adalah pertanyaan C #, tetapi obat generik juga digunakan dalam bahasa lain, dan kegunaan / tujuannya sangat mirip.

Koleksi Java menggunakan generik sejak Java 1.5. Jadi, tempat yang baik untuk menggunakannya adalah saat Anda membuat objek seperti koleksi Anda sendiri.

Contoh yang saya lihat hampir di mana-mana adalah kelas Pair, yang menampung dua objek, tetapi perlu menangani objek-objek itu dengan cara yang umum.

class Pair<F, S> {
    public final F first;
    public final S second;

    public Pair(F f, S s)
    { 
        first = f;
        second = s;   
    }
}  

Setiap kali Anda menggunakan kelas Pair ini, Anda dapat menentukan jenis objek yang Anda inginkan untuk ditangani dan masalah cast jenis apa pun akan muncul pada waktu kompilasi, bukan waktu proses.

Generik juga dapat memiliki batasan yang ditentukan dengan kata kunci 'super' dan 'extends'. Misalnya, jika Anda ingin berurusan dengan tipe generik tetapi Anda ingin memastikannya memperluas kelas yang disebut Foo (yang memiliki metode setTitle):

public class FooManager <F extends Foo>{
    public void setTitle(F foo, String title) {
        foo.setTitle(title);
    }
}

Meskipun tidak terlalu menarik, penting untuk diketahui bahwa setiap kali Anda berurusan dengan FooManager, Anda tahu bahwa FooManager akan menangani tipe MyClass, dan MyClass memperluas Foo.


2

Dari dokumentasi Sun Java, sebagai tanggapan atas "mengapa saya harus menggunakan obat generik?":

"Generik menyediakan cara bagi Anda untuk mengkomunikasikan jenis koleksi ke kompilator, sehingga dapat diperiksa. Setelah kompilator mengetahui jenis elemen dari koleksi, kompilator dapat memeriksa bahwa Anda telah menggunakan koleksi secara konsisten dan dapat menyisipkan cor yang benar pada nilai yang diambil dari koleksi ... Kode yang menggunakan generik lebih jelas dan lebih aman .... kompiler dapat memverifikasi pada waktu kompilasi bahwa batasan jenis tidak dilanggar pada waktu proses [penekanan saya]. Karena kompilasi program tanpa peringatan, kita dapat menyatakan dengan pasti bahwa itu tidak akan memunculkan ClassCastException pada saat dijalankan. Efek bersih dari penggunaan generik, terutama dalam program besar, adalah peningkatan keterbacaan dan ketahanan . [penekanan saya] "


Saya tidak pernah menemukan kasus di mana pengetikan generik dari koleksi akan membantu kode saya. Koleksiku memiliki cakupan yang ketat. Itulah mengapa saya mengucapkan ini "Bisakah itu membantu saya?". Sebagai pertanyaan sampingan, apakah Anda mengatakan bahwa sebelum Anda mulai menggunakan obat generik, hal ini kadang-kadang terjadi pada Anda? (menempatkan jenis objek yang salah dalam koleksi Anda). Bagi saya ini seperti solusi tanpa masalah nyata, tapi mungkin saya hanya beruntung.
Bill K

@Bill K: jika kode dikontrol dengan ketat (yaitu, hanya digunakan oleh Anda) mungkin Anda tidak akan pernah menganggap ini sebagai masalah. Itu hebat! Risiko terbesar ada dalam proyek besar yang dikerjakan oleh banyak orang, IMO. Ini adalah jaring pengaman, dan "praktik terbaik".
Demi

@Bill K: Ini adalah contohnya. Katakanlah Anda memiliki metode yang mengembalikan ArrayList. Katakanlah ArrayList bukanlah koleksi umum. Kode seseorang mengambil ArrayList ini dan mencoba melakukan beberapa operasi pada itemnya. Satu-satunya masalah adalah Anda mengisi ArrayList dengan BillTypes, dan konsumen mencoba mengoperasikan ConsumerTypes. Ini mengkompilasi, tetapi meledak selama runtime. Jika Anda menggunakan koleksi generik, Anda akan mengalami kesalahan kompiler, yang jauh lebih baik untuk ditangani.
Demi

@Bill K: Saya telah bekerja dengan orang-orang dengan tingkat keahlian yang sangat bervariasi. Saya tidak memiliki kemewahan untuk memilih dengan siapa saya berbagi proyek. Jadi, keamanan tipe sangat penting bagi saya. Ya, saya telah menemukan (dan mengoreksi) bug dengan mengonversi kode untuk menggunakan Generik.
Eddie

1

Generik memungkinkan Anda membuat objek yang sangat diketik, namun Anda tidak perlu menentukan tipe spesifik. Saya pikir contoh terbaik yang berguna adalah List dan kelas serupa.

Menggunakan daftar umum Anda dapat memiliki Daftar Daftar Daftar apa pun yang Anda inginkan dan Anda selalu dapat merujuk pada pengetikan yang kuat, Anda tidak perlu mengonversi atau apa pun seperti yang Anda lakukan dengan Array atau Daftar standar.


1

Generik memungkinkan Anda menggunakan pengetikan yang kuat untuk objek dan struktur data yang dapat menampung objek apa pun. Ini juga menghilangkan typecast yang membosankan dan mahal saat mengambil objek dari struktur generik (tinju / unboxing).

Salah satu contoh yang menggunakan keduanya adalah daftar tertaut. Apa gunanya kelas daftar tertaut jika hanya bisa menggunakan objek Foo? Untuk mengimplementasikan daftar tertaut yang dapat menangani segala jenis objek, daftar tertaut dan node dalam kelas dalam node hipotetis harus bersifat umum jika Anda ingin daftar hanya berisi satu jenis objek.


1

Jika koleksi Anda berisi tipe nilai, mereka tidak perlu mengemas / melepas kotak ke objek saat dimasukkan ke dalam koleksi sehingga kinerja Anda meningkat secara dramatis. Add-on keren seperti resharper dapat menghasilkan lebih banyak kode untuk Anda, seperti foreach loop.


1

Keuntungan lain menggunakan Generik (terutama dengan Koleksi / Daftar) adalah Anda mendapatkan Pemeriksaan Jenis Waktu Kompilasi. Ini sangat berguna saat menggunakan Daftar Generik daripada Daftar Objek.


1

Satu-satunya alasan adalah mereka menyediakan keamanan Tipe

List<Customer> custCollection = new List<Customer>;

sebagai lawan,

object[] custCollection = new object[] { cust1, cust2 };

sebagai contoh sederhana.


Ketik keamanan, diskusi itu sendiri. Mungkin seseorang harus bertanya tentang itu.
MrBoJangles

Ya tapi apa yang kamu maksud? Inti dari Keamanan Tipe?
Vin

1

Singkatnya, obat generik memungkinkan Anda untuk menentukan lebih tepat apa yang ingin Anda lakukan (pengetikan lebih kuat).

Ini memiliki beberapa manfaat untuk Anda:

  • Karena kompilator mengetahui lebih banyak tentang apa yang ingin Anda lakukan, ini memungkinkan Anda untuk menghilangkan banyak pengecoran tipe karena kompiler sudah tahu bahwa tipe tersebut akan kompatibel.

  • Ini juga memberi Anda umpan balik lebih awal tentang kebenaran program Anda. Hal-hal yang sebelumnya akan gagal pada waktu proses (misalnya, karena sebuah objek tidak dapat di-cast dalam jenis yang diinginkan), sekarang gagal pada waktu kompilasi dan Anda dapat memperbaiki kesalahan sebelum departemen pengujian mengajukan laporan bug kriptikal.

  • Kompiler dapat melakukan lebih banyak pengoptimalan, seperti menghindari tinju, dll.


1

Beberapa hal untuk ditambahkan / dikembangkan (berbicara dari sudut pandang .NET):

Tipe generik memungkinkan Anda membuat kelas dan antarmuka berbasis peran. Ini telah dikatakan sudah dalam istilah yang lebih mendasar, tetapi saya menemukan Anda mulai merancang kode Anda dengan kelas yang diimplementasikan dengan cara tipe-agnostik - yang menghasilkan kode yang sangat dapat digunakan kembali.

Argumen umum tentang metode dapat melakukan hal yang sama, tetapi argumen tersebut juga membantu menerapkan prinsip "Katakan Jangan Tanya" untuk casting, yaitu "berikan apa yang saya inginkan, dan jika Anda tidak bisa, beri tahu saya alasannya".


1

Saya menggunakannya sebagai contoh di sebuah GenericDao yang diimplementasikan dengan SpringORM dan Hibernate yang terlihat seperti ini

public abstract class GenericDaoHibernateImpl<T> 
    extends HibernateDaoSupport {

    private Class<T> type;

    public GenericDaoHibernateImpl(Class<T> clazz) {
        type = clazz;
    }

    public void update(T object) {
        getHibernateTemplate().update(object);
    }

    @SuppressWarnings("unchecked")
    public Integer count() {
    return ((Integer) getHibernateTemplate().execute(
        new HibernateCallback() {
            public Object doInHibernate(Session session) {
                    // Code in Hibernate for getting the count
                }
        }));
    }
  .
  .
  .
}

Dengan menggunakan generik, implementasi saya dari DAO ini memaksa pengembang untuk meneruskan mereka hanya entitas yang dirancang untuk mereka hanya dengan subclass GenericDao

public class UserDaoHibernateImpl extends GenericDaoHibernateImpl<User> {
    public UserDaoHibernateImpl() {
        super(User.class);     // This is for giving Hibernate a .class
                               // work with, as generics disappear at runtime
    }

    // Entity specific methods here
}

Kerangka kecil saya lebih kuat (memiliki hal-hal seperti pemfilteran, pemuatan lambat, pencarian). Saya baru saja menyederhanakan di sini untuk memberi Anda contoh

Saya, seperti Steve dan Anda, mengatakan di awal "Terlalu berantakan dan rumit" tetapi sekarang saya melihat kelebihannya


1

Manfaat yang jelas seperti "type safety" dan "no casting" sudah disebutkan, jadi mungkin saya bisa berbicara tentang beberapa "manfaat" lain yang saya harap ini membantu.

Pertama-tama, generik adalah konsep bahasa-independen dan, IMO, mungkin lebih masuk akal jika Anda memikirkan polimorfisme reguler (waktu proses) pada saat yang sama.

Sebagai contoh, polimorfisme seperti yang kita ketahui dari desain berorientasi objek memiliki gagasan runtime di mana objek pemanggil ditemukan pada saat runtime saat eksekusi program berjalan dan metode yang relevan dipanggil sesuai dengan jenis runtime. Dalam obat generik, idenya agak mirip tetapi semuanya terjadi pada waktu kompilasi. Apa artinya itu dan bagaimana Anda memanfaatkannya?

(Mari tetap menggunakan metode umum untuk membuatnya tetap kompak) Ini berarti Anda masih dapat memiliki metode yang sama pada kelas terpisah (seperti yang Anda lakukan sebelumnya di kelas polimorfik) tetapi kali ini mereka dibuat secara otomatis oleh kompilator bergantung pada jenis yang ditetapkan pada waktu kompilasi. Anda mengatur metode Anda pada tipe yang Anda berikan pada waktu kompilasi. Jadi, alih-alih menulis metode dari awal untuk setiap jenis Anda miliki seperti yang Anda lakukan dalam polimorfisme runtime ( metode), Anda membiarkan kompiler melakukan pekerjaan selama kompilasi. Ini memiliki keuntungan yang jelas karena Anda tidak perlu menyimpulkan semua kemungkinan jenis yang mungkin digunakan di sistem Anda yang membuatnya jauh lebih skalabel tanpa perubahan kode.

Kelas bekerja dengan cara yang hampir sama. Anda parametrise tipe dan kode yang dihasilkan oleh kompilator.

Setelah Anda mendapatkan ide tentang "waktu kompilasi", Anda dapat menggunakan jenis "terbatas" dan membatasi apa yang dapat diteruskan sebagai jenis parameter melalui kelas / metode. Jadi, Anda dapat mengontrol apa yang akan dilalui yang merupakan hal yang kuat terutama Anda memiliki kerangka yang dikonsumsi oleh orang lain.

public interface Foo<T extends MyObject> extends Hoo<T>{
    ...
}

Tidak ada yang bisa menyetel sth selain MyObject sekarang.

Selain itu, Anda bisa "menerapkan" batasan jenis pada argumen metode Anda yang berarti Anda bisa memastikan kedua argumen metode Anda akan bergantung pada tipe yang sama.

public <T extends MyObject> foo(T t1, T t2){
    ...
}   

Semoga semua ini masuk akal.



0

Menggunakan obat generik untuk koleksi sangatlah sederhana dan bersih. Bahkan jika Anda menaruhnya di tempat lain, keuntungan dari koleksi adalah kemenangan bagi saya.

List<Stuff> stuffList = getStuff();
for(Stuff stuff : stuffList) {
    stuff.do();
}

vs.

List stuffList = getStuff();
Iterator i = stuffList.iterator();
while(i.hasNext()) {
    Stuff stuff = (Stuff)i.next();
    stuff.do();
}

atau

List stuffList = getStuff();
for(int i = 0; i < stuffList.size(); i++) {
    Stuff stuff = (Stuff)stuffList.get(i);
    stuff.do();
}

Itu saja sepadan dengan "biaya" marjinal obat generik, dan Anda tidak perlu menjadi Guru generik untuk menggunakan ini dan mendapatkan nilai.


1
Tanpa obat generik, Anda dapat melakukan: List stuffList = getStuff (); untuk (Object stuff: stuffList) {((Stuff) stuff) .doStuff (); }, yang tidak jauh berbeda.
Tom Hawtin - tackline

Tanpa obat generik saya melakukan stuffList.doAll (); Saya berkata bahwa saya selalu memiliki kelas pembungkus yang merupakan tempat untuk kode seperti itu. Jika tidak, bagaimana Anda menghindari menyalin loop ini di tempat lain? Di mana Anda menaruhnya untuk digunakan kembali? Kelas pembungkus mungkin akan memiliki semacam loop, tetapi di kelas itu, karena kelas itu adalah tentang "Hal-hal", menggunakan loop yang dicor untuk seperti yang disarankan Tom di atas cukup jelas / mendokumentasikan sendiri.
Bill K

@Jherico, Itu sangat menarik. Saya ingin tahu apakah ada alasan Anda merasa seperti itu, dan jika itu yang saya tidak mengerti - bahwa ada sesuatu di alam manusia yang menemukan casting untuk alasan apa pun cabul dan bersedia melakukan hal yang tidak wajar (seperti menambahkan sintaks yang jauh lebih kompleks) untuk menghindarinya. Mengapa "Jika Anda harus melemparkan sesuatu, Anda sudah kalah"?
Bill K

@Jherico: menurut dokumentasi Sun, obat generik memberi kompiler pengetahuan tentang tujuan cast objek. Karena kompilator melakukan casting untuk generik, bukan untuk pengguna, apakah ini mengubah pernyataan Anda?
Demi

Saya telah mengubah kode dari pra Java 1.5 ke Generik, dan dalam prosesnya menemukan bug di mana tipe objek yang salah dimasukkan ke dalam koleksi. Saya juga termasuk dalam kamp "jika Anda harus melempar, Anda telah kalah", karena jika Anda harus melakukan transmisi secara manual, Anda berisiko mengalami ClassCastException. Dengan Generics, compiler melakukannya tanpa terlihat untuk Anda, tetapi kemungkinan ClassCastException jauh berkurang karena keamanan tipe. Ya, tanpa Generik Anda bisa menggunakan Object, tapi itu bau kode yang mengerikan bagi saya, sama seperti "throws Exception".
Eddie

0

Generik juga memberi Anda kemampuan untuk membuat lebih banyak objek / metode yang dapat digunakan kembali sambil tetap memberikan dukungan khusus jenis. Anda juga mendapatkan banyak performa dalam beberapa kasus. Saya tidak tahu spesifikasi lengkapnya tentang Java Generics, tetapi di .NET saya dapat menentukan batasan pada parameter Type, seperti Menerapkan Antarmuka, Pembuat, dan Turunan.


0
  1. Mengaktifkan pemrogram untuk mengimplementasikan algoritme generik - Dengan menggunakan algoritme generik, pemrogram dapat mengimplementasikan algoritme generik yang bekerja pada kumpulan jenis berbeda, dapat disesuaikan, dan aman untuk tipe serta lebih mudah dibaca.

  2. Pemeriksaan jenis yang lebih kuat pada waktu kompilasi - Pengompilasi Java menerapkan pemeriksaan jenis yang kuat ke kode umum dan mengeluarkan kesalahan jika kode tersebut melanggar keamanan jenis. Memperbaiki kesalahan waktu kompilasi lebih mudah daripada memperbaiki kesalahan waktu proses, yang mungkin sulit ditemukan.

  3. Penghapusan gips.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.