Apa alasan saya tidak bisa membuat tipe array generik di Jawa?


273

Apa alasan mengapa Java tidak mengizinkan kami melakukannya

private T[] elements = new T[initialCapacity];

Saya bisa mengerti. NET tidak mengizinkan kami untuk melakukan itu, seperti dalam. NET Anda memiliki tipe nilai yang pada saat run-time dapat memiliki ukuran yang berbeda, tetapi di Jawa semua jenis T akan menjadi referensi objek, sehingga memiliki ukuran yang sama ( koreksi saya jika saya salah).

Apa alasannya?


29
Apa yang kamu bicarakan? Anda benar-benar dapat melakukan ini di .NET. - Saya di sini mencoba mencari tahu mengapa saya tidak bisa melakukannya di Jawa.
BrainSlugs83

@ BrainSlugs83 - silakan tambahkan tautan ke beberapa contoh kode atau tutorial yang menunjukkan itu.
MasterJoe2


1
@ MasterJoe2 kode di atas dalam pertanyaan OP adalah yang saya maksud. Ini berfungsi dengan baik di C #, tetapi tidak di Jawa. - Pertanyaan menyatakan tidak berfungsi, yang mana tidak benar. - Tidak yakin ada nilai dalam membahasnya lebih lanjut.
BrainSlugs83

Jawaban:


204

Itu karena array Java (tidak seperti generik) berisi, pada saat runtime, informasi tentang tipe komponennya. Jadi, Anda harus tahu tipe komponen saat membuat array. Karena Anda tidak tahu apa Titu saat runtime, Anda tidak bisa membuat array.


29
Tapi bagaimana dengan penghapusan? Mengapa itu tidak berlaku?
Qix - MONICA DISALAHKAN

14
Lalu bagaimana ArrayList <SomeType>caranya?
Thumbz

10
@ Thumbz: Maksud Anda new ArrayList<SomeType>()? Tipe generik tidak mengandung parameter tipe saat runtime. Parameter tipe tidak digunakan dalam pembuatan. Tidak ada perbedaan dalam kode yang dihasilkan oleh new ArrayList<SomeType>()atau new ArrayList<String>()atau new ArrayList()sama sekali.
newacct

8
Saya bertanya lebih lanjut tentang cara ArrayList<T>kerjanya dengan ' private T[] myArray. Di suatu tempat dalam kode, itu harus memiliki array tipe T generik, jadi bagaimana?
Thumbz

21
@ Thumbz: Itu tidak memiliki array tipe runtime T[]. Ini memiliki larik tipe runtime Object[], dan 1) kode sumber berisi variabel Object[](ini adalah bagaimana itu dalam sumber Java Java terbaru); atau 2) kode sumber berisi variabel tipe T[], yang merupakan kebohongan, tetapi tidak menyebabkan masalah karena Tdihapus di dalam ruang lingkup kelas.
Newacct

137

Mengutip:

Array tipe generik tidak diperbolehkan karena tidak bersuara. Masalahnya adalah karena interaksi array Java, yang tidak suara statis tetapi diperiksa secara dinamis, dengan obat generik, yang suara statis dan tidak diperiksa secara dinamis. Inilah cara Anda dapat mengeksploitasi celah:

class Box<T> {
    final T x;
    Box(T x) {
        this.x = x;
    }
}

class Loophole {
    public static void main(String[] args) {
        Box<String>[] bsa = new Box<String>[3];
        Object[] oa = bsa;
        oa[0] = new Box<Integer>(3); // error not caught by array store check
        String s = bsa[0].x; // BOOM!
    }
}

Kami telah mengusulkan untuk menyelesaikan masalah ini menggunakan array yang aman secara statis (alias Variance) tetapi ditolak untuk Tiger.

- gafter

(Saya percaya itu adalah Neal Gafter , tetapi saya tidak yakin)

Lihat dalam konteks di sini: http://forums.sun.com/thread.jspa?threadID=457033&forumID=316


3
Perhatikan bahwa saya membuatnya menjadi CW karena jawabannya bukan milik saya.
Bart Kiers

10
Ini menjelaskan mengapa itu mungkin bukan typesafe. Tapi masalah keamanan tipe bisa diperingatkan oleh kompiler. Faktanya adalah bahwa hal itu bahkan tidak mungkin dilakukan, karena alasan yang hampir sama mengapa Anda tidak dapat melakukannya new T(). Setiap array di Jawa, dengan desain, menyimpan tipe komponen (yaitu T.class) di dalamnya; Oleh karena itu Anda memerlukan kelas T saat runtime untuk membuat array seperti itu.
Newacct

2
Anda masih dapat menggunakan new Box<?>[n], yang kadang-kadang cukup, meskipun itu tidak membantu dalam contoh Anda.
Bartosz Klimek

1
@ BartKiers Saya tidak mengerti ... ini masih tidak dapat dikompilasi (java-8): Box<String>[] bsa = new Box<String>[3];apakah ada perubahan di java-8 dan ke atas saya berasumsi?
Eugene

1
@Eugene, Array tipe generik spesifik tidak diizinkan karena dapat menyebabkan hilangnya keamanan tipe seperti yang ditunjukkan dalam sampel. Itu tidak diizinkan di versi Java apa pun. Jawabannya dimulai dengan "Array tipe generik tidak diperbolehkan karena tidak bersuara."
garnet

47

Dengan gagal memberikan solusi yang layak, Anda hanya berakhir dengan IMHO sesuatu yang lebih buruk.

Pekerjaan umum di sekitar adalah sebagai berikut.

T[] ts = new T[n];

diganti dengan (dengan asumsi T memperluas Object dan bukan kelas lain)

T[] ts = (T[]) new Object[n];

Saya lebih suka contoh pertama, tetapi lebih banyak tipe akademis yang lebih suka contoh kedua, atau lebih suka tidak memikirkannya.

Sebagian besar contoh mengapa Anda tidak bisa hanya menggunakan Obyek [] sama-sama berlaku untuk Daftar atau Koleksi (yang didukung), jadi saya melihatnya sebagai argumen yang sangat buruk.

Catatan: ini adalah salah satu alasan perpustakaan Koleksi itu sendiri tidak mengkompilasi tanpa peringatan. Jika Anda menggunakan case ini tidak dapat didukung tanpa peringatan, ada sesuatu yang pada dasarnya rusak dengan model generik IMHO.


6
Anda harus berhati-hati dengan yang kedua. Jika Anda mengembalikan array yang dibuat sedemikian rupa kepada seseorang yang mengharapkan, katakanlah, a String[](atau jika Anda menyimpannya di bidang yang dapat diakses secara publik dari tipe T[], dan seseorang mengambilnya), maka mereka akan mendapatkan ClassCastException.
berita baru

4
Saya memilih jawaban ini karena contoh pilihan Anda tidak diizinkan di Jawa dan contoh kedua Anda dapat melempar ClassCastException
José Roberto Araújo Júnior

5
@ JoséRobertoAraújoJúnior Cukup jelas contoh pertama perlu diganti dengan contoh kedua. Akan lebih membantu bagi Anda untuk menjelaskan mengapa contoh kedua dapat melempar ClassCastException karena tidak akan jelas bagi semua orang.
Peter Lawrey

3
@PeterLawrey Saya membuat pertanyaan yang dijawab sendiri yang menunjukkan mengapa T[] ts = (T[]) new Object[n];itu ide yang buruk: stackoverflow.com/questions/21577493/...
José Roberto Araújo Júnior

1
@MarkoTopolnik Saya harus diberikan medali untuk menjawab semua komentar Anda untuk menjelaskan hal yang sama dengan yang telah saya katakan, satu-satunya hal yang berubah dari alasan saya semula adalah saya pikir dia mengatakan T[] ts = new T[n];itu adalah contoh yang valid. Saya akan memilih karena jawaban dia dapat menyebabkan masalah dan kebingungan kepada devs lain dan juga di luar topik. Juga, saya akan berhenti berkomentar tentang ini.
José Roberto Araújo Júnior

38

Array adalah Covarian

Array dikatakan kovarian yang pada dasarnya berarti bahwa, mengingat aturan subtyping Jawa, array tipe T[]dapat berisi elemen tipe Tatau subtipe apa pun dari T. Misalnya

Number[] numbers = new Number[3];
numbers[0] = newInteger(10);
numbers[1] = newDouble(3.14);
numbers[2] = newByte(0);

Tetapi tidak hanya itu, aturan subtipe Jawa juga menyatakan bahwa array S[]adalah subtipe array T[]jika Smerupakan subtipe T, maka, sesuatu seperti ini juga valid:

Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;

Karena menurut aturan subtyping di Jawa, array Integer[]adalah subtipe dari array Number[]karena Integer adalah subtipe dari Number.

Tetapi aturan subtyping ini dapat menimbulkan pertanyaan menarik: apa yang akan terjadi jika kita mencoba melakukan ini?

myNumber[0] = 3.14; //attempt of heap pollution

Baris terakhir ini akan mengkompilasi dengan baik, tetapi jika kita menjalankan kode ini, kita akan mendapatkan ArrayStoreExceptionkarena kita mencoba untuk menempatkan ganda ke dalam array integer. Fakta bahwa kita mengakses array melalui referensi Number tidak relevan di sini, yang penting array adalah array integer.

Ini berarti bahwa kita dapat mengelabui kompiler, tetapi kita tidak dapat menipu sistem tipe run-time. Dan ini terjadi karena array adalah apa yang kita sebut tipe yang dapat diverifikasi. Ini berarti bahwa pada saat run-time Java tahu bahwa array ini sebenarnya dipakai sebagai array integer yang kebetulan diakses melalui referensi tipe Number[].

Jadi, seperti yang bisa kita lihat, satu hal adalah jenis objek yang sebenarnya, satu hal lagi adalah jenis referensi yang kita gunakan untuk mengaksesnya, bukan?

Masalah dengan Java Generics

Sekarang, masalah dengan tipe generik di Jawa adalah bahwa informasi tipe untuk parameter tipe dibuang oleh kompiler setelah kompilasi kode dilakukan; oleh karena itu informasi jenis ini tidak tersedia pada saat dijalankan. Proses ini disebut tipe erasure . Ada alasan bagus untuk mengimplementasikan obat generik seperti ini di Jawa, tapi itu cerita panjang, dan itu ada hubungannya dengan kompatibilitas biner dengan kode yang sudah ada sebelumnya.

Poin penting di sini adalah karena pada saat run-time tidak ada informasi jenis, tidak ada cara untuk memastikan bahwa kami tidak melakukan polusi timbunan.

Mari pertimbangkan sekarang kode tidak aman berikut:

List<Integer> myInts = newArrayList<Integer>();
myInts.add(1);
myInts.add(2);
List<Number> myNums = myInts; //compiler error
myNums.add(3.14); //heap polution

Jika kompiler Java tidak menghentikan kita dari melakukan ini, sistem tipe run-time tidak dapat menghentikan kita juga, karena pada saat run time, tidak ada cara untuk menentukan bahwa daftar ini seharusnya hanya menjadi daftar bilangan bulat saja. Run-time Java akan membiarkan kita memasukkan apa pun yang kita inginkan ke dalam daftar ini, padahal seharusnya hanya berisi bilangan bulat, karena ketika dibuat, itu dinyatakan sebagai daftar bilangan bulat. Itu sebabnya kompiler menolak baris nomor 4 karena tidak aman dan jika dibiarkan bisa mematahkan asumsi sistem tipe.

Dengan demikian, para perancang Java memastikan bahwa kita tidak dapat membodohi kompiler. Jika kita tidak dapat membodohi kompiler (seperti yang dapat kita lakukan dengan array) maka kita juga tidak bisa menipu sistem tipe run-time.

Karena itu, kami mengatakan bahwa tipe generik tidak dapat diverifikasi, karena pada saat dijalankan kami tidak dapat menentukan sifat sebenarnya dari tipe generik.

Saya melewatkan beberapa bagian dari jawaban ini, Anda dapat membaca artikel lengkap di sini: https://dzone.com/articles/covariance-and-contravariance


32

Alasan ini tidak mungkin adalah bahwa Java mengimplementasikan Generiknya murni pada tingkat kompiler, dan hanya ada satu file kelas yang dihasilkan untuk setiap kelas. Ini disebut Penghapusan Jenis .

Saat runtime, kelas yang dikompilasi perlu menangani semua penggunaannya dengan bytecode yang sama. Jadi, new T[capacity]sama sekali tidak tahu tipe apa yang perlu dipakai.


17

Jawabannya sudah diberikan tetapi jika Anda sudah memiliki Mesin Virtual maka Anda dapat melakukan ini:

T t; //Assuming you already have this object instantiated or given by parameter.
int length;
T[] ts = (T[]) Array.newInstance(t.getClass(), length);

Semoga, saya bisa membantu, Ferdi265


1
Ini solusi yang bagus. Tetapi ini akan mendapatkan peringatan yang tidak dicentang (dilemparkan dari Obyek ke T []). Lain "lambat" tetapi solusi "warning-free" akan menjadi: T[] ts = t.clone(); for (int i=0; i<ts.length; i++) ts[i] = null;.
midnite

1
Selain itu, jika apa yang kita simpan adalah T[] t, maka itu akan menjadi (T[]) Array.newInstance(t.getClass().getComponentType(), length);. Saya memang menghabiskan beberapa waktu untuk mencari tahu getComponentType(). Semoga ini bisa membantu orang lain.
midnite

1
@midnite t.clone()tidak akan kembali T[]. Karena ttidak Array dalam jawaban ini.
xmen

6

Alasan utama adalah karena fakta bahwa array di Jawa adalah kovarian.

Ada ikhtisar yang bagus di sini .


Saya tidak melihat bagaimana Anda dapat mendukung "T baru [5]" bahkan dengan array yang tidak berubah.
Dimitris Andreou

2
@ DimitrisAndreou Yah, semuanya agak komedi kesalahan dalam desain Java. Semuanya dimulai dengan array kovarians. Kemudian, setelah Anda memiliki array yang kovarians, Anda dapat melemparkan String[]ke Objectdan menyimpan Integerdi dalamnya. Jadi mereka harus menambahkan pemeriksaan runtime type untuk array store ( ArrayStoreException) karena masalah tidak dapat ditangkap pada waktu kompilasi. (Kalau tidak, Integersebenarnya bisa terjebak dalam String[], dan Anda akan mendapatkan kesalahan ketika Anda mencoba mengambilnya, yang akan mengerikan.) ...
Radon Rosborough

2
@ DimitrisAndreou ... Kemudian, setelah Anda meletakkan runtime check di tempat cek kompilasi waktu yang jauh lebih terdengar, Anda mengalami penghapusan tipe (juga cacat desain yang tidak menguntungkan - termasuk hanya untuk kompatibilitas ke belakang). Penghapusan tipe berarti bahwa Anda tidak dapat melakukan pemeriksaan tipe runtime untuk tipe generik. Jadi karena itu, untuk menghindari masalah tipe penyimpanan array, Anda tidak dapat memiliki array generik. Jika mereka hanya membuat array invarian di tempat pertama, kita bisa melakukan pemeriksaan tipe waktu kompilasi tanpa menjalankan pelanggaran penghapusan.
Radon Rosborough

... Saya baru saja menemukan periode pengeditan lima menit untuk komentar. Objectseharusnya Object[]di komentar pertama saya.
Radon Rosborough

3

Saya suka jawaban yang diberikan secara tidak langsung oleh Gafter . Namun, saya mengusulkan itu salah. Saya mengubah sedikit kode Gafter. Itu mengkompilasi dan berjalan untuk sementara waktu kemudian meledak di mana Gafter memperkirakan itu akan terjadi

class Box<T> {

    final T x;

    Box(T x) {
        this.x = x;
    }
}

class Loophole {

    public static <T> T[] array(final T... values) {
        return (values);
    }

    public static void main(String[] args) {

        Box<String> a = new Box("Hello");
        Box<String> b = new Box("World");
        Box<String> c = new Box("!!!!!!!!!!!");
        Box<String>[] bsa = array(a, b, c);
        System.out.println("I created an array of generics.");

        Object[] oa = bsa;
        oa[0] = new Box<Integer>(3);
        System.out.println("error not caught by array store check");

        try {
            String s = bsa[0].x;
        } catch (ClassCastException cause) {
            System.out.println("BOOM!");
            cause.printStackTrace();
        }
    }
}

Outputnya adalah

I created an array of generics.
error not caught by array store check
BOOM!
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at Loophole.main(Box.java:26)

Jadi menurut saya Anda dapat membuat tipe array generik di java. Apakah saya salah paham pertanyaannya?


Contoh Anda berbeda dari apa yang saya tanyakan. Apa yang Anda jelaskan adalah bahaya kovarian array. Lihatlah (untuk .NET: blogs.msdn.com/b/ericlippert/archive/2007/10/17/… )
melahap elysium

Semoga Anda mendapatkan peringatan keamanan jenis dari kompiler, ya?
Matt McHenry

1
Ya, saya mendapatkan peringatan keamanan jenis. Ya, saya melihat bahwa contoh saya tidak responsif terhadap pertanyaan.
emory

Sebenarnya Anda mendapatkan banyak peringatan karena inisialisasi ceroboh dari a, b, c. Juga, ini dikenal dan mempengaruhi perpustakaan inti, mis. <T> java.util.Arrays.asList (T ...). Jika Anda melewatkan tipe T yang tidak dapat diverifikasi, Anda akan mendapatkan peringatan (karena array yang dibuat memiliki tipe yang kurang tepat daripada kode yang ditiru), dan itu super jelek. Akan lebih baik jika pembuat metode ini mendapat peringatan, alih-alih memancarkannya di situs penggunaan, mengingat metode itu sendiri aman, tidak memunculkan array ke pengguna.
Dimitris Andreou

1
Anda tidak membuat larik generik di sini. Kompiler membuat larik (non-generik) untuk Anda.
Newacct

2

Saya tahu saya sedikit terlambat ke pesta di sini, tetapi saya pikir saya mungkin bisa membantu para googler di masa depan karena tidak ada jawaban yang memperbaiki masalah saya. Jawaban Ferdi265 sangat membantu.

Saya mencoba membuat daftar Linked saya sendiri, jadi kode berikut ini berfungsi untuk saya:

package myList;
import java.lang.reflect.Array;

public class MyList<TYPE>  {

    private Node<TYPE> header = null;

    public void clear() {   header = null;  }

    public void add(TYPE t) {   header = new Node<TYPE>(t,header);    }

    public TYPE get(int position) {  return getNode(position).getObject();  }

    @SuppressWarnings("unchecked")
    public TYPE[] toArray() {       
        TYPE[] result = (TYPE[])Array.newInstance(header.getObject().getClass(),size());        
        for(int i=0 ; i<size() ; i++)   result[i] = get(i); 
        return result;
    }


    public int size(){
         int i = 0;   
         Node<TYPE> current = header;
         while(current != null) {   
           current = current.getNext();
           i++;
        }
        return i;
    }  

Dalam metode toArray () terletak cara untuk membuat array tipe generik untuk saya:

TYPE[] result = (TYPE[])Array.newInstance(header.getObject().getClass(),size());    

2

Dalam kasus saya, saya hanya ingin berbagai tumpukan, seperti ini:

Stack<SomeType>[] stacks = new Stack<SomeType>[2];

Karena ini tidak mungkin, saya menggunakan yang berikut sebagai solusi:

  1. Membuat kelas pembungkus non-generik di sekitar Stack (katakanlah MyStack)
  2. MyStack [] tumpukan = new MyStack [2] bekerja dengan sangat baik

Jelek, tapi Jawa senang.

Catatan: seperti yang disebutkan oleh BrainSlugs83 dalam komentar pertanyaan, sangat mungkin untuk memiliki array generik di .NET


2

Dari tutorial Oracle :

Anda tidak dapat membuat array tipe parameter. Misalnya, kode berikut ini tidak dikompilasi:

List<Integer>[] arrayOfLists = new List<Integer>[2];  // compile-time error

Kode berikut menggambarkan apa yang terjadi ketika berbagai tipe dimasukkan ke dalam array:

Object[] strings = new String[2];
strings[0] = "hi";   // OK
strings[1] = 100;    // An ArrayStoreException is thrown.

Jika Anda mencoba hal yang sama dengan daftar generik, akan ada masalah:

Object[] stringLists = new List<String>[];  // compiler error, but pretend it's allowed
stringLists[0] = new ArrayList<String>();   // OK
stringLists[1] = new ArrayList<Integer>();  // An ArrayStoreException should be thrown,
                                            // but the runtime can't detect it.

Jika array daftar parameter diijinkan, kode sebelumnya akan gagal untuk membuang ArrayStoreException yang diinginkan.

Bagi saya, itu terdengar sangat lemah. Saya pikir siapa pun yang memiliki pemahaman generik yang memadai, akan baik-baik saja, dan bahkan berharap, bahwa ArrayStoredException tidak dilemparkan dalam kasus seperti itu.


0

Tentunya harus ada cara yang baik di sekitarnya (mungkin menggunakan refleksi), karena menurut saya itulah yang sebenarnya ArrayList.toArray(T[] a)terjadi. Saya mengutip:

public <T> T[] toArray(T[] a)

Mengembalikan array yang mengandung semua elemen dalam daftar ini dalam urutan yang benar; tipe runtime dari array yang dikembalikan adalah array yang ditentukan. Jika daftar sesuai dengan array yang ditentukan, itu dikembalikan di dalamnya. Jika tidak, array baru dialokasikan dengan tipe runtime dari array yang ditentukan dan ukuran daftar ini.

Jadi salah satu cara mengatasinya adalah dengan menggunakan fungsi ini yaitu membuat ArrayListobjek yang Anda inginkan dalam array, kemudian gunakantoArray(T[] a) untuk membuat array aktual. Ini tidak akan cepat, tetapi Anda tidak menyebutkan persyaratan Anda.

Jadi, adakah yang tahu bagaimana toArray(T[] a)penerapannya?


3
List.toArray (T []) berfungsi karena Anda pada dasarnya memberikannya tipe komponen T saat runtime (Anda memberinya contoh tipe array yang diinginkan, dari mana ia bisa mendapatkan kelas array, dan kemudian, kelas komponen T ). Dengan tipe komponen aktual saat runtime, Anda selalu dapat membuat larik tipe runtime itu menggunakan Array.newInstance(). Anda akan menemukan bahwa disebutkan dalam banyak pertanyaan yang menanyakan cara membuat array dengan tipe yang tidak dikenal pada waktu kompilasi. Tetapi OP secara khusus menanyakan mengapa Anda tidak dapat menggunakan new T[]sintaksis, yang merupakan pertanyaan yang berbeda
newacct

0

Itu karena generik ditambahkan ke java setelah mereka membuatnya, jadi itu agak kikuk karena pembuat asli java berpikir bahwa ketika membuat array tipe akan ditentukan dalam pembuatannya. Jadi itu tidak bekerja dengan obat generik sehingga Anda harus melakukan E [] array = (E []) Obyek baru [15]; Ini mengkompilasi tetapi memberi peringatan.


0

Jika kita tidak dapat membuat instance array generik, mengapa bahasa tersebut memiliki tipe array generik? Apa gunanya memiliki tipe tanpa objek?

Satu-satunya alasan yang dapat saya pikirkan adalah varargs - foo(T...). Kalau tidak, mereka bisa sepenuhnya menggosok jenis array generik. (Yah, mereka tidak benar-benar harus menggunakan array untuk varargs, karena vararg tidak ada sebelum 1.5 . Itu mungkin kesalahan lain.)

Jadi itu bohong, Anda bisa instantiate array generik, melalui varargs!

Tentu saja, masalah dengan array generik masih nyata, misalnya

static <T> T[] foo(T... args){
    return args;
}
static <T> T[] foo2(T a1, T a2){
    return foo(a1, a2);
}

public static void main(String[] args){
    String[] x2 = foo2("a", "b"); // heap pollution!
}

Kita dapat menggunakan contoh ini untuk benar-benar menunjukkan bahaya array generik .

Di sisi lain, kami telah menggunakan vararg generik selama satu dekade, dan langit belum jatuh. Jadi kita bisa berargumen bahwa masalahnya dibesar-besarkan; ini bukan masalah besar. Jika pembuatan larik generik eksplisit diizinkan, kami akan memiliki bug di sana-sini; tapi kita sudah terbiasa dengan masalah penghapusan, dan kita bisa hidup dengannya.

Dan kita dapat menunjuk untuk foo2membantah klaim bahwa spek itu menjauhkan kita dari masalah yang mereka klaim untuk menjaga kita. Jika Sun memiliki lebih banyak waktu dan sumber daya untuk 1,5 , saya percaya mereka bisa mencapai resolusi yang lebih memuaskan.


0

Seperti yang telah disebutkan orang lain, tentu saja Anda dapat membuat melalui beberapa trik .

Tapi itu tidak disarankan.

Karena tipe penghapusan dan yang lebih penting covariancearray dalam yang hanya memungkinkan array subtipe dapat ditugaskan ke array supertipe, yang memaksa Anda untuk menggunakan tipe cast eksplisit ketika mencoba untuk mendapatkan nilai kembali menyebabkan run-time ClassCastExceptionyang merupakan salah satu tujuan utama yang coba dihilangkan oleh obat generik: Pemeriksaan tipe yang lebih kuat pada waktu kompilasi .

Object[] stringArray = { "hi", "me" };
stringArray[1] = 1;
String aString = (String) stringArray[1]; // boom! the TypeCastException

Contoh lebih langsung dapat ditemukan di Java Efektif: Item 25 .


covariance : array tipe S [] adalah subtipe dari T [] jika S adalah subtipe dari T


0

Jika kelas menggunakan sebagai tipe parameter, ia dapat mendeklarasikan array bertipe T [], tetapi ia tidak dapat langsung membuat array seperti itu. Sebagai gantinya, pendekatan umum adalah untuk instantiate array dari tipe Object [], dan kemudian membuat cast penyempitan untuk mengetik T [], seperti yang ditunjukkan pada berikut ini:

  public class Portfolio<T> {
  T[] data;
 public Portfolio(int capacity) {
   data = new T[capacity];                 // illegal; compiler error
   data = (T[]) new Object[capacity];      // legal, but compiler warning
 }
 public T get(int index) { return data[index]; }
 public void set(int index, T element) { data[index] = element; }
}

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.