Karena Java tidak memiliki larik generik, saya menggunakan trik biasa untuk mentransmisikan larik Objek ke parameter tipe. Ini berfungsi dengan baik ketika saya memiliki parameter tipe formal seperti <T> tetapi tidak ketika saya menggunakan parameter tipe terbatas <T extends something>.

Mengikuti Kode menggunakan tipe formal berfungsi dengan baik

public class Deck <T> {
    private T [] cards;
    private int size;

    public Deck () {
        cards = (T []) new Object[52];
        size = 0;
    }
}

public class BlackJackGame {
    Deck<BlackJackCard> deck;

    public BlackJackGame() {
        deck = new Deck<>();
        populate (deck);
        deck.shuffle();
    }
}

public class BlackJackCard extends Card {
}

Kode berikut menggunakan kesalahan lemparan tipe terbatas

public class Deck <T extends Card> {
    private T [] cards;
    private int size;

    public Deck () {
        cards = (T []) new Object[52];
        size = 0;
    }
}

public class BlackJackGame {
    Deck<BlackJackCard> deck;

    public BlackJackGame() {
        deck = new Deck<>();
        populate (deck);
        deck.shuffle();
    }
}

public class BlackJackCard extends Card {
}
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [LCard;
    at Deck.<init>(Deck.java:10)
    at BlackJackGame.<init>(BlackJackGame.java:5)
2
abb 21 September 2019, 02:42

1 menjawab

Jawaban Terbaik

Contoh ini mengingatkan saya pada hari-hari awal, ketika saya membaca tentang Generik di buku "Java Efektif" ...

Hal pertama yang pertama, di sini adalah aturan emas generik java: jangan campurkan array dan generik, karena Anda mendapatkan peluang bagus untuk menghasilkan kode yang tidak aman. Kode Anda mencampur obat generik (misalnya T, T extends Card) dengan array (misalnya kartu T []). Kemudian, Anda mendapat kode tidak aman di runtime.

Ini adalah salah satu cara yang aman (lebih suka daftar daripada array):

class Deck <T extends Card> {
    private List<T> cards;

    public Deck () {
        cards = new ArrayList()<>;
    }

}

Sekarang, untuk menjawab pertanyaan Anda, Anda harus kembali ke beberapa dasar terlebih dahulu di java:

1- Array adalah konstruksi co-variant

2- Generik adalah konstruksi invarian

3- Jenis Elemen direifikasi dalam array (reifikasi)

4- Tipe Parameter dihapus dalam Generik (Penghapusan tipe)

Jangan khawatir, kesampingkan konsep menakutkan, dan periksa apa yang terjadi dengan contoh Anda:

  • Tipe T Formal terhapus di Runtime.

  • Itu berarti itu benar-benar dihapus dalam bytecode.

  • Dalam contoh pertama T baru saja diganti dengan Object, karena itu adalah kelas terdekat (dalam hal pewarisan) jadi,

cards = (T []) new Object[52]

Diterjemahkan menjadi

cards = (Object []) new Object[52];

Yang aman.

  • Dalam contoh ke-2 T terikat ke Kartu dan menjadi , karenanya, kelas terdekat dengannya (dalam hal pewarisan) jadi,
cards = (T []) new Object[52]

Diterjemahkan menjadi

cards = (Card []) new Object[52];

Karena Object bukan subtipe dari Card, Anda mendapatkan pengecualian cast Runtime.

6
Zbair Lahcen 21 September 2019, 12:52