1. Semua kelas mewarisiObject

Semua kelas di Java secara implisit mewarisi Objectkelas tersebut.

Kami akan menganalisis apa itu warisan dan bagaimana cara kerjanya di Java dalam pencarian Java Core. Untuk saat ini, kami akan mempertimbangkan satu fakta sederhana yang mengikuti dari ini:

Objek dari kelas apa pun dapat ditugaskan ke Objectvariabel. Contoh:

Kode Catatan
Object o = new Scanner(System.in);
Variabel omenyimpan referensi ke Scannerobjek
Object o = new String();
Variabel omenyimpan referensi ke Stringobjek
Object o = new Integer(15);
Variabel omenyimpan referensi ke Integerobjek
Object o = "Hello";
Variabel omenyimpan referensi ke Stringobjek

Di sinilah kabar baik berakhir. Kompiler tidak melacak jenis objek asli yang disimpan dalam Objectvariabel, jadi Anda tidak akan bisa memanggil metode pada objek yang disimpan selain metode kelas Object.

Jika Anda perlu memanggil metode yang terkait dengan tipe asli objek, maka Anda harus terlebih dahulu menyimpan referensi ke dalam variabel dengan tipe yang benar, lalu memanggil metode pada variabel itu:

Kode Catatan
Object o = new Scanner(System.in);
int x = o.nextInt();
Program tidak akan dikompilasi. Kelas Objecttidak memiliki nextInt()metode.
Object o = new Scanner(System.in);

Scanner console = (Scanner) o;

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

Di sini kita menyimpan referensi ke Scannerobjek dalam Scannervariabel menggunakan operator typecast .

Anda tidak bisa begitu saja pergi dan menetapkan Objectvariabel ke variabel Pemindai, bahkan jika Objectvariabel tersebut menyimpan referensi Scannerobjek. Tapi Anda bisa melakukan ini jika menggunakan operator typecast , yang sudah Anda ketahui. Ini penampakan umumnya:

Type name1 = (Type) name2;

Di mana name1nama variabel Type, dan name2nama Objectvariabel yang menyimpan referensi ke suatu Typeobjek.

Pengetikan

Jika tipe variabel dan tipe objek tidak cocok, maka a ClassCastExceptionakan dilempar. Contoh:

Kode Catatan
Object o = new Integer(5);
String s = (String) o;
Kesalahan akan terjadi saat runtime:
a ClassCastExceptionakan dilempar ke sini

Ada cara untuk menghindari kesalahan ini di Java: kita melakukannya dengan memeriksa jenis objek yang disimpan dalam variabel :

name instanceof Type

Operator instanceofmemeriksa apakah namevariabel adalah Typeobjek.

Sebagai contoh, mari kita temukan sebuah string dalam array dari berbagai objek:

Kode 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 mengonversi nilai ini menjadi Integer, String, dan Double, berturut-turut.

Ulangi array objek

Jika objeknya adalah String

Simpan ke Stringvariabel
Tampilkan variabel di layar.


2. Mengapa obat generik muncul — koleksi

Mari kembali ke koleksi.

Segera setelah pengembang Java membuat ArrayListkelas, mereka ingin menjadikannya universal, sehingga dapat menyimpan semua jenis objek. Jadi mereka menggunakan larik Objects untuk menyimpan elemen.

Kekuatan dari pendekatan ini adalah Anda dapat menambahkan objek jenis apa pun ke koleksi.

Tentu saja, ada beberapa kelemahan.

Kerugian 1.

Itu selalu diperlukan untuk menulis operator konversi tipe saat mengambil elemen dari koleksi:

Kode 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);
}
Buat koleksi untuk menyimpan referensi ke Objectobjek

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



Menjumlahkan elemen koleksi


Pengetikan diperlukan

Kerugian 2.

Tidak ada jaminan bahwa koleksi berisi jenis elemen tertentu

Kode 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);
}
Buat koleksi untuk menyimpan referensi ke Objectobjek

Kami mengisi koleksi dengan angka yang direpresentasikan sebagai Doubleobjek:
0.0, 2.5, 5.0, ...


Menjumlahkan elemen koleksi


Akan ada kesalahan: a Doubletidak dapat dilemparkan keInteger

Data dapat dimasukkan ke dalam koleksi di mana saja:

  • dalam metode lain
  • dalam program lain
  • dari file
  • melalui jaringan

Kerugian 3.

Data dalam koleksi dapat diubah secara tidak sengaja.

Anda dapat meneruskan koleksi yang diisi dengan data Anda ke beberapa metode. Metode tersebut, yang ditulis oleh pemrogram lain, menambahkan datanya ke koleksi Anda.

Nama koleksi tidak secara jelas menunjukkan jenis data apa yang dapat disimpan di dalamnya. Dan bahkan jika Anda memberikan variabel Anda nama yang jelas, referensi ke sana dapat diteruskan ke selusin metode, dan metode tersebut pasti tidak akan tahu apa-apa tentang nama asli variabel tersebut.


3. Generik

Generik di Jawa

Di Jawa, semua masalah ini dihilangkan dengan hal keren yang disebut obat generik.

Di Java, generik berarti kemampuan untuk menambahkan parameter tipe ke tipe. Hasilnya adalah tipe komposit yang kompleks. Pandangan umum dari jenis komposit semacam itu adalah sebagai berikut:

ClassName<TypeParameter>

Ini adalah kelas generik. Dan itu dapat digunakan di mana pun Anda biasanya menggunakan kelas.

Kode Keterangan
ArrayList<Integer> list;
Membuat variabel
list = new ArrayList<Integer> ();
Membuat objek
ArrayList<Integer>[] array;
Membuat array

Hanya Integervariabel yang dapat disimpan dalam koleksi seperti itu:

Kode Keterangan
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(new Integer(1));
list.add(2);
list.add("Hello");
ArrayListkoleksi dengan Integerelemen
Ini diizinkan
Dan ini juga akan berfungsi
Kotak otomatis

Tapi ini tidak diperbolehkan: kesalahan kompilasi

Anda akan belajar cara membuat kelas Anda sendiri dengan parameter tipe dalam pencarian Java Collections. Untuk saat ini, kita akan melihat cara menggunakannya dan cara kerjanya.


4. Cara kerja obat generik

Sebenarnya, obat generik sangat primitif.

Kompiler hanya mengganti tipe generik dengan tipe biasa. Tetapi ketika metode tipe generik digunakan, kompiler menambahkan operator typecast untuk mentransmisikan parameter ke parameter tipe:

Kode Apa yang dilakukan oleh kompiler
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);

Misalkan kita memiliki metode yang menjumlahkan angka dalam kumpulan bilangan bulat:

Kode Apa yang dilakukan oleh kompiler
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;
}

Dengan kata lain, obat generik adalah sejenis gula sintaksis, seperti autoboxing, tetapi lebih sedikit. Dengan autoboxing, kompiler menambahkan metode untuk mengonversi an intke an Integerdan sebaliknya, dan untuk obat generik ia menambahkan operator typecast.

Setelah kompiler mengkompilasi kelas generik Anda dengan parameter tipe, mereka hanya diubah menjadi kelas biasa dan operator typecast. Informasi tentang argumen tipe yang diteruskan ke variabel tipe generik hilang. Efek ini juga disebut type erasure .

Terkadang pemrogram yang menulis kelas generik (kelas dengan parameter tipe) sangat membutuhkan informasi tentang tipe yang diteruskan sebagai argumen. Dalam pencarian Java Collections, Anda akan belajar bagaimana menangani ini dan apa yang dibutuhkannya.



5. Beberapa fakta tentang obat generik

Berikut adalah beberapa fakta menarik tentang obat generik.

Kelas dapat memiliki beberapa parameter tipe. Ini terlihat seperti ini:

ClassName<TypeParameter1, TypeParameter2, TypeParameter3>

Sebenarnya, ini tidak terlalu mengejutkan. Di mana pun kompiler dapat menambahkan operator untuk dilemparkan ke satu jenis, itu dapat menambahkan beberapa operator typecast.

Contoh:

Kode Catatan
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(7, "Hello");
map.put(-15, "Hello");
Parameter pertama metode putadalah an Integer, dan yang kedua adalah aString

Tipe generik juga dapat digunakan sebagai parameter . Ini terlihat seperti ini:

ClassName<TypeParameter<TypeParameterParameter>>

Misalkan kita ingin membuat daftar yang akan menyimpan daftar string. Dalam hal ini, kita akan mendapatkan 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);

Tipe generik (tipe dengan parameter tipe) juga dapat digunakan sebagai tipe array. Ini terlihat seperti ini:

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

Tidak ada yang ajaib terjadi di sini: tanda kurung sudut hanya menunjukkan nama jenis:

Kode Mitra non-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];