Token Jenis Super dalam Generik Java

1. Gambaran keseluruhan

Dalam tutorial ini, kita akan membiasakan diri dengan token jenis super dan melihat bagaimana mereka dapat membantu kita mengekalkan maklumat jenis generik pada waktu runtime.

2. Pemadaman

Kadang kala kita perlu menyampaikan maklumat jenis tertentu dengan kaedah . Sebagai contoh, di sini kami menjangkakan dari Jackson untuk menukar array byte JSON ke String:

byte[] data = // fetch json from somewhere String json = objectMapper.readValue(data, String.class);

Kami menyampaikan harapan ini melalui token kelas literal, dalam kes ini, kelas String.class.

Walau bagaimanapun, kami tidak dapat menetapkan harapan yang sama untuk jenis generik dengan mudah:

Map json = objectMapper.readValue(data, Map.class); // won't compile

Java memadam maklumat jenis generik semasa penyusunan. Oleh itu, parameter jenis generik hanyalah artifak kod sumber dan tidak akan ada pada waktu proses.

2.1. Pembaharuan

Secara teknikal, jenis generik tidak disatukan kembali di Jawa. Dalam terminologi bahasa pengaturcaraan, apabila jenis ada pada waktu runtime, kita mengatakan bahawa jenis itu diperbaiki.

Jenis yang disatukan di Jawa adalah seperti berikut:

  • Jenis primitif sederhana seperti panjang
  • Abstraksi bukan generik seperti String atau Runnable
  • Jenis mentah seperti List atau HashMap
  • Jenis generik di mana semua jenis adalah wildcard tanpa had seperti List atau HashMap
  • Susunan jenis lain yang disatukan seperti String [], int [], List [], atau Map []

Oleh itu, kita tidak dapat menggunakan sesuatu seperti Map.class kerana Peta bukanlah jenis yang disatukan.

3. Token Jenis Super

Ternyata, kita dapat memanfaatkan kekuatan kelas dalaman tanpa nama di Java untuk mengekalkan maklumat jenis semasa waktu penyusunan:

public abstract class TypeReference { private final Type type; public TypeReference() { Type superclass = getClass().getGenericSuperclass(); type = ((ParameterizedType) superclass).getActualTypeArguments()[0]; } public Type getType() { return type; } }

Kelas ini abstrak, jadi kami hanya dapat memperoleh subkelas daripadanya.

Sebagai contoh, kita boleh membuat dalaman tanpa nama:

TypeReference token = new TypeReference() {};

Pembina melakukan langkah-langkah berikut untuk mengekalkan maklumat jenis:

  • Pertama, ia mendapat metadata superclass generik untuk contoh ini - dalam kes ini, superclass generik adalah TypeReference
  • Kemudian, ia mendapatkan dan menyimpan parameter jenis sebenar untuk superclass generik - dalam kes ini, ia adalah Peta

Pendekatan ini untuk mengekalkan maklumat jenis generik biasanya dikenali sebagai token jenis super :

TypeReference token = new TypeReference() {}; Type type = token.getType(); assertEquals("java.util.Map", type.getTypeName()); Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments(); assertEquals("java.lang.String", typeArguments[0].getTypeName()); assertEquals("java.lang.Integer", typeArguments[1].getTypeName());

Dengan menggunakan token jenis super, kita tahu bahawa jenis kontena adalah Peta, dan juga, parameter jenisnya ialah String dan Integer.

Corak ini begitu terkenal sehingga perpustakaan seperti Jackson dan kerangka seperti Spring mempunyai pelaksanaannya sendiri. Menghuraikan objek JSON ke dalam Peta dapat dicapai dengan menentukan jenis itu dengan token jenis super:

TypeReference token = new TypeReference() {}; Map json = objectMapper.readValue(data, token);

4. Kesimpulan

Dalam tutorial ini, kami belajar bagaimana kami dapat menggunakan token jenis super untuk mengekalkan maklumat jenis generik pada waktu runtime.

Seperti biasa, semua contoh boleh didapati di GitHub.