1. Semua kelas mewarisiObject

Semua kelas di Jawa secara tersirat mewarisi Objectkelas tersebut.

Kami akan menganalisis apakah warisan dan cara ia berfungsi dalam Java dalam pencarian Java Core. Buat masa ini, kami akan mempertimbangkan satu fakta mudah yang berikut daripada ini:

Objek dari mana-mana kelas boleh diberikan kepada Objectpembolehubah. Contoh:

Kod Catatan
Object o = new Scanner(System.in);
Pembolehubah omenyimpan rujukan kepada Scannerobjek
Object o = new String();
Pembolehubah omenyimpan rujukan kepada Stringobjek
Object o = new Integer(15);
Pembolehubah omenyimpan rujukan kepada Integerobjek
Object o = "Hello";
Pembolehubah omenyimpan rujukan kepada Stringobjek

Di sinilah berita baik itu berakhir. Pengkompil tidak menjejaki jenis objek asal yang disimpan dalam Objectpembolehubah, jadi anda tidak akan dapat memanggil kaedah pada objek yang disimpan selain daripada kaedah kelas Object.

Jika anda perlu memanggil kaedah yang dikaitkan dengan jenis asal objek, maka anda perlu terlebih dahulu menyimpan rujukan kepadanya dalam pembolehubah jenis yang betul, dan kemudian memanggil kaedah pada pembolehubah itu:

Kod Catatan
Object o = new Scanner(System.in);
int x = o.nextInt();
Program tidak akan disusun. Kelas Objecttidak mempunyai nextInt()kaedah.
Object o = new Scanner(System.in);

Scanner console = (Scanner) o;

int x = console.nextInt();
Ini akan berjaya.

Di sini kami menyimpan rujukan kepada Scannerobjek dalam Scannerpembolehubah menggunakan operator taip .

Anda tidak boleh pergi dan menetapkan Objectpembolehubah kepada pembolehubah Pengimbas, walaupun Objectpembolehubah itu menyimpan rujukan Scannerobjek. Tetapi anda boleh melakukan ini jika anda menggunakan operator taip , yang sudah anda ketahui. Ini adalah penampilan umumnya:

Type name1 = (Type) name2;

Di manakah name1nama pembolehubah Type, dan name2ialah nama Objectpembolehubah yang menyimpan rujukan kepada Typeobjek.

Typecasting

Jika jenis pembolehubah dan jenis objek tidak sepadan, maka a ClassCastExceptionakan dilemparkan. Contoh:

Kod Catatan
Object o = new Integer(5);
String s = (String) o;
Ralat akan berlaku semasa runtime:
a ClassCastExceptionakan dilemparkan ke sini

Terdapat cara untuk mengelakkan ralat ini dalam Java: kami melakukan ini dengan menyemak jenis objek yang disimpan dalam pembolehubah :

name instanceof Type

Operator instanceofmenyemak sama ada namepembolehubah adalah Typeobjek.

Sebagai contoh, mari kita cari rentetan dalam pelbagai objek yang pelbagai:

Kod Catatan
Object[] objects = {10, "Hello", 3.14};

for (int i = 0; i < objects.length; i++)
{
   if (objects[i] instanceof String)
   {
      String s = (String) objects[i];
      System.out.println(s);
   }
}
Autoboxing akan menukar nilai ini kepada Integer, String, dan Double, masing-masing.

Gelung ke atas tatasusunan objek

Jika objek ialah String

Simpan ke Stringpembolehubah
Paparkan pembolehubah pada skrin.


2. Mengapa generik muncul — koleksi

Mari kembali kepada koleksi.

Sebaik sahaja pembangun Java mencipta ArrayListkelas, mereka mahu menjadikannya universal, supaya ia boleh menyimpan sebarang jenis objek. Jadi mereka menggunakan tatasusunan Objects untuk menyimpan elemen.

Kekuatan pendekatan ini ialah anda boleh menambah objek dalam apa jua jenis pada koleksi.

Sudah tentu, terdapat beberapa kelemahan.

Kelemahan 1.

Ia sentiasa perlu untuk menulis operator penukaran jenis apabila mendapatkan semula elemen daripada koleksi:

Kod Catatan
ArrayList numbers = new ArrayList();


for (int i = 0; i < 10; i++)
   numbers.add(i * 10);


int sum = 0;
for (int i = 0; i < 10; i++)
{
   sum = sum + (Integer) numbers.get(i);
}
Cipta koleksi untuk menyimpan rujukan kepada Objectobjek

Isi koleksi dengan nombor 10, 20, ... 100;



Jumlahkan elemen koleksi


Typecasting adalah perlu

Kelemahan 2.

Tiada jaminan bahawa koleksi mengandungi jenis elemen tertentu

Kod Catatan
ArrayList numbers = new ArrayList();


for (int i = 0; i < 10; i++)
   numbers.add(i * 2.5);


int sum = 0;
for (int i = 0; i < 10; i++)
{
   sum = sum + (Integer) numbers.get(i);
}
Cipta koleksi untuk menyimpan rujukan kepada Objectobjek

Kami mengisi koleksi dengan nombor yang diwakili sebagai Doubleobjek:
0.0, 2.5, 5.0, ...


Jumlahkan elemen koleksi


Akan terdapat ralat: a Doubletidak boleh dihantar keInteger

Data boleh dimasukkan ke dalam koleksi di mana-mana sahaja:

  • dalam kaedah lain
  • dalam program lain
  • daripada fail
  • melalui rangkaian

Kelemahan 3.

Data dalam koleksi boleh ditukar secara tidak sengaja.

Anda boleh menghantar koleksi yang diisi dengan data anda kepada beberapa kaedah. Kaedah itu, yang ditulis oleh pengaturcara yang berbeza, menambahkan datanya pada koleksi anda.

Nama koleksi tidak menunjukkan dengan jelas jenis data yang boleh disimpan di dalamnya. Dan walaupun anda memberikan nama yang jelas kepada pembolehubah anda, rujukan kepadanya boleh dihantar kepada sedozen kaedah, dan kaedah tersebut pastinya tidak akan mengetahui apa-apa tentang nama asal pembolehubah itu.


3. Generik

Generik di Jawa

Di Jawa, semua masalah ini dihapuskan oleh perkara hebat ini yang dipanggil generik.

Di Java, generik bermaksud keupayaan untuk menambah parameter jenis pada jenis. Hasilnya ialah jenis komposit yang kompleks. Pandangan umum jenis komposit sedemikian adalah ini:

ClassName<TypeParameter>

Ini adalah kelas generik. Dan ia boleh digunakan di mana sahaja anda biasa menggunakan kelas.

Kod Penerangan
ArrayList<Integer> list;
Mencipta pembolehubah
list = new ArrayList<Integer> ();
Mencipta objek
ArrayList<Integer>[] array;
Mencipta tatasusunan

Hanya Integerpembolehubah boleh disimpan dalam koleksi sedemikian:

Kod Penerangan
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(new Integer(1));
list.add(2);
list.add("Hello");
ArrayListkoleksi dengan Integerelemen
Ini dibenarkan
Dan ini juga akan berfungsi
Autoboxing

Tetapi ini tidak dibenarkan: ralat penyusunan

Anda akan belajar cara membuat kelas anda sendiri dengan parameter jenis dalam pencarian Java Collections. Buat masa ini, kita akan melihat cara menggunakannya dan cara ia berfungsi.


4. Cara generik berfungsi

Sebenarnya, generik adalah sangat primitif.

Pengkompil hanya menggantikan jenis generik dengan jenis biasa. Tetapi apabila kaedah jenis generik digunakan, pengkompil menambah operator taip untuk menghantar parameter kepada parameter jenis:

Kod Apa yang dilakukan oleh pengkompil
ArrayList<Integer> list = new ArrayList<Integer>();
ArrayList list = new ArrayList();
list.add(1);
list.add( (Integer) 1 );
int x = list.get(0);
int x = (Integer) list.get(0);
list.set(0, 10);
list.set(0, (Integer) 10);

Katakan kita mempunyai kaedah yang menjumlahkan nombor dalam koleksi integer:

Kod Apa yang dilakukan oleh pengkompil
public int sum(ArrayList<Integer> numbers)
{
   int result = 0;

   for (int i = 0; i < numbers.size(); i++)
      result = result + numbers.get(i);

   return result;
}
public int sum(ArrayList numbers)
{
   int result = 0;

   for (int i = 0; i < numbers.size(); i++)
      result = result + (Integer) numbers.get(i);

   return result;
}

Dalam erti kata lain, generik adalah sejenis gula sintaksis, sama seperti autoboxing, tetapi lebih sedikit. Dengan autoboxing, pengkompil menambah kaedah untuk menukar an intkepada an Integerdan sebaliknya, dan untuk generik ia menambah operator taip.

Selepas pengkompil menyusun kelas generik anda dengan parameter jenis, ia hanya ditukar kepada kelas biasa dan operator taip. Maklumat tentang jenis argumen yang dihantar kepada pembolehubah jenis generik hilang. Kesan ini juga dipanggil pemadaman jenis .

Kadangkala pengaturcara menulis kelas generik (kelas dengan parameter jenis) benar-benar memerlukan maklumat tentang jenis yang diluluskan sebagai hujah. Dalam pencarian Java Collections, anda akan belajar cara menangani perkara ini dan perkara yang diperlukan.



5. Sedikit fakta tentang generik

Berikut adalah beberapa fakta menarik tentang generik.

Kelas boleh mempunyai beberapa jenis parameter. Ia kelihatan seperti ini:

ClassName<TypeParameter1, TypeParameter2, TypeParameter3>

Sebenarnya, ini tidak terlalu mengejutkan. Di mana-mana pengkompil boleh menambah operator untuk menghantar kepada satu jenis, ia boleh menambah berbilang operator taip.

Contoh:

Kod Catatan
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(7, "Hello");
map.put(-15, "Hello");
Parameter pertama kaedah putialah a Integer, dan yang kedua ialah aString

Jenis generik juga boleh digunakan sebagai parameter . Ia kelihatan seperti ini:

ClassName<TypeParameter<TypeParameterParameter>>

Katakan kita ingin membuat senarai yang akan menyimpan senarai rentetan. Dalam kes ini, kita akan mendapat sesuatu seperti ini:

// List of greetings
ArrayList<String> listHello = new ArrayList<String>();
listHello.add ("Hello");
listHello.add ("Hi");

// List of goodbyes
ArrayList<String> listBye = new ArrayList<String>();
listBye.add("Bye");
listBye.add ("Goodbye");

// List of lists
ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
lists.add(listHello);
lists.add(listBye);

Jenis generik (jenis dengan parameter jenis) juga boleh digunakan sebagai jenis tatasusunan. Ia kelihatan seperti ini:

ClassName<TypeParameter>[] array = new ClassName<TypeParameter>[size];

Tiada apa-apa yang ajaib berlaku di sini: kurungan sudut hanya menunjukkan nama jenis:

Kod Rakan sejawatan bukan generik
ArrayList<String>[] list = new ArrayList<String>[10];
StringArrayList[] list = new StringArrayList[10];
ArrayList<Integer>[] list = new ArrayList<Integer>[10];
IntegerArrayList[] list = new IntegerArrayList[10];
ArrayList<Scanner>[] list = new ArrayList<Scanner>[10];
ScannerArrayList[] list = new ScannerArrayList[10];