Java 101: Bahasa Java yang penting menampilkan lawatan, Bahagian 5

Sebelumnya 1 2 Halaman 2 Halaman 2 dari 2

Taip inferensi dan pembina generik untuk kelas generik dan bukan generik

Kelas generik dan bukan generik boleh menyatakan pembina generik di mana konstruktor mempunyai senarai parameter jenis formal. Sebagai contoh, anda boleh menyatakan kelas generik berikut dengan pembina generik:

 public class Box { public  Box(T t) { // ... } } 

Deklarasi ini menentukan kelas generik Boxdengan parameter jenis formal E. Ia juga menentukan konstruktor generik dengan parameter jenis formal T. Anda boleh memberi contoh kelas generik dan menggunakan pembentuknya seperti berikut:

 new Box("Aggies") 

Ungkapan ini mencipta contoh Box, berlalu Marbleke E. Juga, penyusun menyimpulkan Stringsebagai Targumen jenis sebenar kerana argumen pembina adalah Stringobjek.

Penyusun Pra-Java 7 menyimpulkan argumen jenis sebenar pembina generik sama dengan kaedah generik. Walau bagaimanapun, penyusun Java 7 dapat menyimpulkan jenis argumen sebenar kelas generik yang dibuat dalam konteks operator berlian. Pertimbangkan contoh berikut:

 Box box = new Box("Aggies"); 

Serta menyimpulkan jenis Marbleuntuk parameter jenis formal Ekelas generik Box, penyusun menyimpulkan jenis Stringuntuk parameter jenis formal Tpembina kelas generik ini.

Perubahan kecil Project Coin # 8: Permintaan kaedah varargs yang dipermudahkan

Sebelum Java 7, setiap usaha untuk menggunakan kaedah varargs (variabel argumen, juga dikenali sebagai variabel arity ) dengan jenis varargs yang tidak dapat diubah semula menyebabkan penyusun mengeluarkan amaran "operasi tidak selamat". Untuk menghilangkan potensi banyak pesan amaran serupa (satu per laman panggilan), Java 7 memindahkan amaran dari laman panggilan ke deklarasi metode.

Jenis yang boleh ditukar dan tidak boleh disahkan semula

A Jenis reifiable mendedahkan jenis maklumat yang lengkap pada masa jalanan. Contohnya termasuk jenis primitif, jenis bukan generik, jenis mentah, dan panggilan kad liar yang tidak terikat. Sebaliknya, jenis yang tidak dapat disahkan semula mempunyai maklumat jenis yang dikeluarkan pada waktu kompilasi dengan penghapusan jenis, untuk memastikan keserasian binari dengan perpustakaan Java dan aplikasi yang dibuat sebelum generik. Contohnya merangkumi Setdan Set. Kerana jenis yang tidak dapat disahkan tidak tersedia sepenuhnya pada waktu runtime, JVM tidak dapat membezakan antara Setdan Set; pada waktu runtime, hanya jenis mentah Setyang ada.

Kaedah generik yang merangkumi parameter input vararg dapat menyebabkan pencemaran timbunan , di mana pemboleh ubah dari jenis parameter merujuk pada objek yang bukan dari jenis parameter tersebut (misalnya jika jenis mentah telah dicampur dengan jenis parameter). Pengkompilasi melaporkan "amaran yang tidak diperiksa" kerana kebenaran operasi yang melibatkan jenis parameter (seperti panggilan atau kaedah panggilan) tidak dapat disahkan.

Penyenaraian 13 menunjukkan pencemaran timbunan dalam konteks bukan-varargs.

Penyenaraian 13. Menunjukkan pencemaran timbunan dalam konteks bukan-varargs

 import java.util.Iterator; import java.util.Set; import java.util.TreeSet; public class HeapPollutionDemo { public static void main(String[] args) { Set s = new TreeSet(); Set ss = s; // unchecked warning s.add(new Integer(42)); // another unchecked warning Iterator iter = ss.iterator(); while (iter.hasNext()) { String str = iter.next(); // ClassCastException thrown System.out.println(str); } } } 

Pemboleh ubah ssmempunyai jenis parameter Set. Apabila java.util.Setyang dirujuk sditugaskan ss, penyusun menghasilkan amaran yang tidak dicentang. Ia melakukannya kerana penyusun tidak dapat menentukan yang smerujuk kepada Setjenis (tidak). Hasilnya ialah pencemaran timbunan. (Pengompil membenarkan tugas ini untuk mengekalkan keserasian ke belakang dengan versi Java lama yang tidak menyokong generik. Tambahan pula, penghapusan jenis berubah Setmenjadi Set, yang mengakibatkan seseorang Setditugaskan kepada yang lain Set.)

Pengkompil menjana amaran dibiarkan kedua pada baris yang menyembah sesuatu Set's add()kaedah. Ia melakukannya kerana tidak dapat menentukan sama ada pemboleh ubah smerujuk kepada Setatau Setjenis. Ini adalah satu lagi keadaan pencemaran timbunan. (Pengkompil ini membolehkan kaedah panggilan ini kerana jelmaan pemadaman Set's boolean add(E e)kaedah untuk boolean add(Object o), yang boleh menambah apa-apa jenis objek yang ditetapkan, termasuk java.lang.Integersubjenis daripada java.lang.Object.)

Pencemaran timbunan boleh berlaku dengan mudah dalam konteks varargs. Sebagai contoh, pertimbangkan Penyenaraian 14.

Penyenaraian 14. Menunjukkan pencemaran timbunan dalam konteks varargs

 import java.util.Arrays; import java.util.List; public class UnsafeVarargsDemo { public static void main(String[] args) { unsafe(Arrays.asList("A", "B", "C"), Arrays.asList("D", "E", "F")); } static void unsafe(List... l) { Object[] oArray = l; oArray[0] = Arrays.asList(new Double(3.5)); String s = l[0].get(0); } } 

The Object[] oArray = l;tugasan memperkenalkan kemungkinan pencemaran timbunan. Nilai yang tidak sepadan dengan jenis parameter parameter varargs ldapat diberikan kepada pemboleh ubah oArray. Walau bagaimanapun, penyusun tidak menghasilkan amaran yang tidak dicentang kerana telah melakukannya semasa menerjemahkan List... lke List[] l. Tugasan ini sah kerana pemboleh ubah lmempunyai jenis List[], yang subtipe Object[].

Juga, pengkompil tidak mengeluarkan amaran atau kesalahan semasa memberikan Listobjek jenis apa pun kepada oArraykomponen array; sebagai contoh , oArray[0] = Arrays.asList(new Double(3.5));. Tugasan ini menyerah hak kepada komponen lokasi pertama oArrayyang Listobjek yang mengandungi satu java.lang.Doubleobjek.

The String s = l[0].get(0);tugasan adalah bermasalah. Objek yang disimpan dalam komponen array pertama pemboleh ubah lmempunyai jenis List, tetapi tugasan ini mengharapkan objek jenis List. Akibatnya, JVM melemparkan java.lang.ClassCastException.

Kumpulkan kod sumber ini ( javac -Xlint:unchecked UnsafeVarargsDemo.java). Anda harus melihat output berikut (sedikit diformat ulang untuk dibaca) ketika disusun di bawah Java SE 7 kemas kini 6:

 UnsafeVarargsDemo.java:8: warning: [unchecked] unchecked generic array creation for varargs parameter of type List[] unsafe(Arrays.asList("A", "B", "C"), ^ UnsafeVarargsDemo.java:12: warning: [unchecked] Possible heap pollution from parameterized vararg type List static void unsafe(List... l) ^ 2 warnings 

Dalam pengenalan Java 101 saya untuk generik, saya menyatakan bahawa anda tidak boleh menggunakan parameter jenis dalam ekspresi penciptaan array. Contohnya, anda tidak dapat menentukan elements = new E[size];. Pengkompilasi melaporkan mesej "ralat penciptaan array generik" apabila anda cuba melakukannya. Walau bagaimanapun, masih mungkin untuk membuat susunan generik, tetapi hanya dalam konteks varargs, dan itulah yang dilaporkan oleh mesej amaran pertama. Di sebalik tabir, penyusun berubah List... lmenjadi List[] ldan kemudian menjadi List[] l.

Perhatikan bahawa amaran pencemaran timbunan dihasilkan di unsafe()laman pengisytiharan kaedah. Mesej ini tidak dihasilkan di laman panggilan kaedah ini, seperti halnya penyusun Java 5 dan 6.

Tidak semua kaedah varargs akan menyumbang kepada pencemaran timbunan. Walau bagaimanapun, mesej amaran masih akan dikeluarkan di laman web deklarasi kaedah. Sekiranya anda tahu bahawa kaedah anda tidak menyumbang kepada pencemaran timbunan, anda boleh menekan amaran ini dengan menyatakannya dengan @SafeVarargsanotasi - Java 7 memperkenalkan java.lang.SafeVarargsjenis anotasi. Sebagai contoh, kerana tidak ada kaedah kaedah Arrayskelas asList()untuk menyumbang kepada pencemaran timbunan, deklarasi kaedah ini telah diberi penjelasan dengan @SafeVarargs, seperti berikut:

 @SafeVarargs public static  List asList(T... a) 

The @SafeVarargsanotasi menghapuskan penciptaan array generik dan mesej amaran pencemaran timbunan. Ini adalah bahagian yang didokumentasikan dari kontrak kaedah dan menegaskan bahawa pelaksanaan kaedah tersebut tidak akan menangani parameter formal varargs secara tidak betul.

Kesimpulannya

Java 7 meningkatkan produktiviti pembangun dengan memperkenalkan pengurusan sumber automatik melalui pernyataan cuba-dengan-sumber bersama dengan AutoCloseableantaramuka baru , beralih-rentetan, multi-tangkapan, rethrow akhir, literal binari, garis bawah dalam literal numerik, perubahan pada jenis kompiler algoritma inferensi yang memperkenalkan pengendali berlian yang disebut, dan pemanggilan kaedah varargs yang dipermudahkan. Seterusnya di Java 101: Siri generasi seterusnya adalah melihat ciri-ciri bahasa antaramuka lambda dan fungsi Java 8's.

Kisah ini, "Java 101: Bahasa Jawa yang penting menampilkan lawatan, Bahagian 5" pada awalnya diterbitkan oleh JavaWorld.