1. Inisialisasi variabel

Seperti yang sudah Anda ketahui, Anda dapat mendeklarasikan beberapa variabel di kelas Anda, dan tidak hanya mendeklarasikannya, tetapi juga segera menginisialisasinya dengan nilai awalnya.

Dan variabel yang sama ini juga dapat diinisialisasi dalam konstruktor. Artinya, secara teori, variabel-variabel ini dapat diberi nilai dua kali. Contoh

Kode Catatan
class Cat
{
   public String name;
   public int age = -1;

   public Cat(String name, int age)
   {
     this.name = name;
     this.age = age;
   }

   public Cat()
   {
     this.name = "Nameless";
   }
}



Variabel agediberi nilai awal




Nilai awal ditimpa


Variabel usia menyimpan nilai awalnya.
 Cat cat = new Cat("Whiskers", 2);
Ini diperbolehkan: konstruktor pertama akan dipanggil
 Cat cat = new Cat();
Ini diperbolehkan: konstruktor kedua akan dipanggil

Inilah yang terjadi ketika Cat cat = new Cat("Whiskers", 2);dieksekusi:

  • Sebuah Catobjek dibuat
  • Semua variabel instan diinisialisasi dengan nilai awalnya
  • Konstruktor dipanggil dan kodenya dieksekusi.

Dengan kata lain, variabel pertama-tama mendapatkan nilai awalnya, dan baru setelah itu kode konstruktor dieksekusi.


2. Urutan inisialisasi variabel dalam suatu kelas

Variabel tidak hanya diinisialisasi sebelum konstruktor berjalan — mereka diinisialisasi dalam urutan yang terdefinisi dengan baik: urutan di mana mereka dideklarasikan di kelas.

Mari kita lihat beberapa kode menarik:

Kode Catatan
public class Solution
{
   public int a = b + c + 1;
   public int b = a + c + 2;
   public int c = a + b + 3;
}

Kode ini tidak akan dikompilasi, karena pada saat avariabel dibuat belum ada b dan c variabel. Tetapi Anda dapat menulis kode Anda seperti berikut — kode ini akan dikompilasi dan akan berjalan dengan baik.

Kode Catatan
public class Solution
{
   public int a;
   public int b = a + 2;
   public int c = a + b + 3;
}


0
0+2
0+2+3

Tapi ingat bahwa kode Anda harus transparan untuk pengembang lain. Lebih baik tidak menggunakan teknik seperti ini, karena merusak keterbacaan kode.

Di sini kita harus ingat bahwa sebelum variabel diberi nilai, mereka memiliki nilai default . Untuk intjenisnya, ini adalah nol.

Ketika JVM menginisialisasi avariabel, itu hanya akan menetapkan nilai default untuk tipe int: 0.

Ketika mencapai b, variabel a sudah diketahui dan memiliki nilai, sehingga JVM akan memberinya nilai 2.

Dan ketika sudah mencapai cvariabel, variabel aand bsudah diinisialisasi, sehingga JVM akan dengan mudah menghitung nilai awal untuk c: 0+2+3.

Jika Anda membuat variabel di dalam metode, Anda tidak dapat menggunakannya kecuali Anda telah menetapkan nilai sebelumnya. Tapi ini tidak berlaku untuk variabel kelas! Jika nilai awal tidak diberikan ke variabel kelas, maka itu diberikan nilai default.


3. Konstanta

Saat kami menganalisis bagaimana objek dibuat, ada baiknya menyentuh inisialisasi konstanta, yaitu variabel dengan pengubah final.

Jika suatu variabel memiliki pengubah final, maka harus diberi nilai awal. Anda sudah mengetahui hal ini, dan tidak ada yang mengejutkan tentang itu.

Tetapi yang tidak Anda ketahui adalah bahwa Anda tidak harus langsung menetapkan nilai awal jika Anda menetapkannya di konstruktor. Ini akan bekerja dengan baik untuk variabel akhir. Satu-satunya persyaratan adalah jika Anda memiliki banyak konstruktor, maka variabel final harus diberi nilai di setiap konstruktor.

Contoh:

public class Cat
{
   public final int maxAge = 25;
   public final int maxWeight;

   public Cat (int weight)
   {
     this.maxWeight = weight; // Assign an initial value to the constant
   }
}


4. Kode dalam konstruktor

Dan beberapa catatan penting lainnya tentang konstruktor. Nanti, saat Anda terus mempelajari Java, Anda akan menemukan hal-hal seperti pewarisan, serialisasi, pengecualian, dll. Semuanya memengaruhi pekerjaan konstruktor dalam derajat yang berbeda-beda. Tidak masuk akal untuk mendalami topik-topik ini sekarang, tetapi kami setidaknya harus menyentuhnya.

Misalnya, inilah komentar penting tentang konstruktor. Secara teori, Anda dapat menulis kode dengan kompleksitas apa pun dalam sebuah konstruktor. Tapi jangan lakukan ini. Contoh:

class FilePrinter
{
   public String content;

   public FilePrinter(String filename) throws Exception
   {
      FileInputStream input = new FileInputStream(filename);
      byte[] buffer = input.readAllBytes();
      this.content = new String(buffer);
   }

   public void printFile()
   {
      System.out.println(content);
   }
}






Buka aliran baca file
Baca file ke dalam array byte
Simpan array byte sebagai string




Tampilkan konten file di layar

Di konstruktor kelas FilePrinter, kami segera membuka aliran byte pada file dan membaca isinya. Ini adalah perilaku yang kompleks dan dapat mengakibatkan kesalahan.

Bagaimana jika tidak ada file seperti itu? Bagaimana jika ada masalah dengan membaca file? Bagaimana jika itu terlalu besar?

Logika kompleks menyiratkan kemungkinan kesalahan yang tinggi dan itu berarti kode harus menangani pengecualian dengan benar.

Contoh 1 — Serialisasi

Dalam program Java standar, ada banyak situasi di mana Anda bukan orang yang membuat objek kelas Anda. Misalnya, Anda memutuskan untuk mengirim objek melalui jaringan: dalam hal ini, mesin Java itu sendiri akan mengubah objek Anda menjadi sekumpulan byte, mengirimkannya, dan membuat ulang objek dari kumpulan byte tersebut.

Tapi anggaplah file Anda tidak ada di komputer lain. Akan ada kesalahan pada konstruktor, dan tidak ada yang akan menanganinya. Dan itu cukup mampu menyebabkan program berhenti.

Contoh 2 — Inisialisasi bidang kelas

Jika konstruktor kelas Anda dapat melempar pengecualian yang diperiksa, yaitu ditandai dengan kata kunci throws, maka Anda harus menangkap pengecualian yang ditunjukkan dalam metode yang membuat objek Anda.

Tetapi bagaimana jika tidak ada metode seperti itu? Contoh:

Kode  Catatan
class Solution
{
   public FilePrinter reader = new FilePrinter("c:\\readme.txt");
}
Kode ini tidak akan dikompilasi.

Konstruktor FilePrinterkelas dapat melontarkan exception yang dicentang , yang berarti Anda tidak dapat membuat FilePrinterobjek tanpa membungkusnya dalam blok try-catch. Dan blok try-catch hanya dapat ditulis dalam sebuah metode



5. Konstruktor kelas dasar

Pada pelajaran sebelumnya, kita sedikit membahas pewarisan. Sayangnya, diskusi lengkap kita tentang pewarisan dan OOP dicadangkan untuk level yang didedikasikan untuk OOP, dan pewarisan konstruktor sudah relevan bagi kita.

Jika kelas Anda mewarisi kelas lain, objek dari kelas induk akan disematkan di dalam objek kelas Anda. Terlebih lagi, kelas induk memiliki variabel dan konstruktornya sendiri.

Itu berarti sangat penting bagi Anda untuk mengetahui dan memahami bagaimana variabel diinisialisasi dan konstruktor dipanggil ketika kelas Anda memiliki kelas induk dan Anda mewarisi variabel dan metodenya.

Kelas

Bagaimana kita mengetahui urutan pemanggilan variabel dan konstruktor? Mari kita mulai dengan menulis kode untuk dua kelas. Yang satu akan mewarisi yang lain:

Kode Catatan
class ParentClass
{
   public String a;
   public String b;

   public ParentClass()
   {
   }
}

class ChildClass extends ParentClass
{
   public String c;
   public String d;

   public ChildClass()
   {
   }
}










Kelas ChildClass mewarisi ParentClasskelas.

Kita perlu menentukan urutan di mana variabel diinisialisasi dan pemanggilan konstruktor. Logging akan membantu kita melakukan ini.

Penebangan

Logging adalah proses merekam tindakan yang dilakukan oleh program saat dijalankan, dengan menuliskannya ke konsol atau file.

Cukup sederhana untuk menentukan bahwa konstruktor telah dipanggil: di badan konstruktor, tulis pesan ke konsol. Tapi bagaimana Anda bisa tahu jika suatu variabel telah diinisialisasi?

Sebenarnya, ini juga tidak terlalu sulit: tulis metode khusus yang akan mengembalikan nilai yang digunakan untuk menginisialisasi variabel, dan log inisialisasi. Seperti inilah tampilan kodenya:

Kode akhir

public class Main
{
   public static void main(String[] args)
   {
      ChildClass obj = new ChildClass();
   }

   public static String print(String text)
   {
      System.out.println(text);
      return text;
   }
}

class ParentClass
{
   public String a = Main.print("ParentClass.a");
   public String b = Main.print("ParentClass.b");

   public ParentClass()
   {
      Main.print("ParentClass.constructor");
   }
}

class ChildClass extends ParentClass
{
   public String c = Main.print("ChildClass.c");
   public String d = Main.print("ChildClass.d");

   public ChildClass()
   {
      Main.print("ChildClass.constructor");
   }
}




Buat ChildClassobjek


Metode ini menulis teks yang diteruskan ke konsol dan juga mengembalikannya.





Deklarasikan teks Tampilan ParentClasskelas

dan juga inisialisasi variabel dengannya.




Tulis pesan bahwa konstruktor telah dipanggil. Abaikan nilai pengembalian.


Deklarasikan teks Tampilan ChildClasskelas

dan juga inisialisasi variabel dengannya.




Tulis pesan bahwa konstruktor telah dipanggil. Abaikan nilai pengembalian.

Jika Anda menjalankan kode ini, teks akan ditampilkan di layar sebagai berikut:

Output konsol dari metode iniMain.print()
ParentClass.a
ParentClass.b
ParentClass.constructor
ChildClass.c
ChildClass.d
ChildClass.constructor

Jadi Anda selalu dapat secara pribadi memastikan bahwa variabel kelas diinisialisasi sebelum konstruktor dipanggil. Kelas dasar diinisialisasi sepenuhnya sebelum inisialisasi kelas yang diwariskan.