CodeGym /Blog Java /rawak /Pembina Java
John Squirrels
Tahap
San Francisco

Pembina Java

Diterbitkan dalam kumpulan
Hai! Hari ini kita akan mempertimbangkan topik yang sangat penting yang berkaitan dengan objek kita. Tanpa keterlaluan, kami boleh katakan anda akan menggunakan topik ini dalam kehidupan sebenar setiap hari! Kami bercakap tentang Java Constructors. Ini mungkin kali pertama anda mendengar istilah ini, tetapi anda sebenarnya telah menggunakan pembina. Anda hanya tidak menyedarinya :) Kami meyakinkan diri kami tentang perkara ini kemudian.

Apakah dalam dunia pembina dan mengapa ia diperlukan?

Mari kita pertimbangkan dua contoh.

public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

       Car bugatti = new Car();
       bugatti.model = "Bugatti Veyron";
       bugatti.maxSpeed = 378;

   }
}
Kami mencipta kereta kami, dan menetapkan model dan kelajuan maksimumnya. Tetapi objek Kereta jelas tidak mempunyai 2 medan dalam projek sebenar. Sebagai contoh, ia mungkin mempunyai 16 medan!

public class Car {

   String model;// model
   int maxSpeed;// maximum speed
   int wheels;// wheel width
   double engineVolume;// engine volume
   String color;// color
   int productionYear;// production year
   String ownerFirstName;// first name of owner
   String ownerLastName;// last name of owner
   long price;// price
   boolean isNew;// flag indicating whether car is new
   int seatsInTheCar;// number of seats in the car
   String cabinMaterial;// interior material
   boolean insurance;// flag indicating whether car is insured
   String manufacturerCountry;// manufacturer country
   int trunkVolume;// size of the trunk
   int accelerationTo100km;// how long it takes to accelerate to 100 km/h (in seconds)


   public static void main(String[] args) {
       Car bugatti = new Car();

       bugatti.color = "blue";
       bugatti.accelerationTo100km = 3;
       bugatti.engineVolume = 6.3;
       bugatti.manufacturerCountry = "Italy";
       bugatti.ownerFirstName = "Amigo";
       bugatti.productionYear = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.seatsInTheCar = 2;
       bugatti.maxSpeed = 378;
       bugatti.model = "Bugatti Veyron";

   }

}
Kami telah mencipta objek Kereta baharu . Terdapat satu masalah: kami mempunyai 16 medan, tetapi kami hanya memulakan 12 ! Lihat kod sekarang dan cuba cari medan yang kami terlupa! Tidak begitu mudah, ya? Dalam keadaan ini, seorang pengaturcara boleh dengan mudah membuat kesilapan dan gagal untuk memulakan beberapa medan. Akibatnya, program akan bertindak secara tidak betul:

public class Car {

   String model;// model
   int maxSpeed;// maximum speed
   int wheels;// wheel width
   double engineVolume;// engine volume
   String color;// color
   int productionYear;// production year
   String ownerFirstName;// first name of owner
   String ownerLastName;// last name of owner
   long price;// price
   boolean isNew;// flag indicating whether car is new
   int seatsInTheCar;// number of seats in the car
   String cabinMaterial;// interior material
   boolean insurance;// flag indicating whether car is insured
   String manufacturerCountry;// manufacturer country
   int trunkVolume;// size of the trunk
   int accelerationTo100km;// how long it takes to accelerate to 100 km/h (in seconds)


   public static void main(String[] args) {
       Car bugatti = new Car();

       bugatti.color = "blue";
       bugatti.accelerationTo100km = 3;
       bugatti.engineVolume = 6.3;
       bugatti.manufacturerCountry = "Italy";
       bugatti.ownerFirstName = "Amigo";
       bugatti.productionYear = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.seatsInTheCar = 2;
       bugatti.maxSpeed = 378;
       bugatti.model = "Bugatti Veyron";

       System.out.println("Model: Bugatti Veyron. Engine volume: " + bugatti.engineVolume + ". Trunk volume: " + bugatti.trunkVolume + ". Cabin material: " + bugatti.cabinMaterial +
       ". Wheel width: " + bugatti.wheels + ". Purchased in 2018 by Mr. " + bugatti.ownerLastName);

   }

}
Output konsol: Model: Bugatti Veyron. Isipadu enjin: 6.3. Isipadu batang: 0. Bahan kabin: null. Lebar roda: 0. Dibeli pada 2018 oleh En. null Pembeli anda, yang menyerahkan $2 juta untuk kereta itu, jelas tidak akan suka dipanggil " Encik null "! Tetapi secara serius, intinya ialah program kami mencipta objek secara tidak betul: kereta dengan lebar roda 0 (iaitu tiada roda sama sekali), batang hilang, kabin diperbuat daripada bahan yang tidak diketahui, dan yang paling penting, pemilik yang tidak ditentukan . Anda hanya boleh bayangkan bagaimana kesilapan sedemikian boleh "padat" apabila program sedang berjalan! Kita perlu mengelak situasi sedemikian entah bagaimana. Kami perlu menyekat program kami: apabila mencipta Kereta baharuobjek, kami mahu medan, seperti model dan kelajuan maksimum, sentiasa ditentukan. Jika tidak, kami mahu menghalang penciptaan objek. Pembina mengendalikan tugas ini dengan mudah. Mereka mendapat nama mereka atas sebab tertentu. Pembina mencipta sejenis "rangka" kelas yang mesti dipadankan oleh setiap objek baharu. Untuk kemudahan, mari kita kembali kepada versi yang lebih ringkas bagi kelas Kereta dengan dua medan. Memandangkan keperluan kami, pembina kelas Kereta akan kelihatan seperti ini:

public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}

// And creating an object now looks like this:

public static void main(String[] args) {
   Car bugatti = new Car("Bugatti Veyron", 378);
}
Perhatikan bagaimana pembina diisytiharkan. Ia serupa dengan kaedah biasa, tetapi ia tidak mempunyai jenis pulangan. Selain itu, pembina menentukan nama kelas ( Kereta ) bermula dengan huruf besar. Selain itu, pembina digunakan dengan kata kunci yang baharu untuk anda: this . Kata kunci ini adalah untuk menunjukkan objek tertentu. Kod dalam pembina

public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
boleh ditafsirkan hampir secara verbatim: " Model untuk kereta ini (yang kita cipta sekarang) ialah hujah model yang diserahkan kepada pembina. MaxSpeed ​​untuk kereta ini (yang kita cipta) ialah hujah maxSpeed ​​yang dihantar kepada pembina." Dan itulah yang berlaku:

public class Car {

   String model;
   int maxSpeed;

   public Car(String model, int maxSpeed) {
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   public static void main(String[] args) {
       Car bugatti = new Car("Bugatti Veyron", 378);
       System.out.println(bugatti.model);
       System.out.println(bugatti.maxSpeed);
   }

}
Output konsol: Bugatti Veyron 378 Pembina memberikan nilai yang diperlukan dengan betul. Anda mungkin perasan bahawa pembina sangat serupa dengan kaedah biasa! Jadi ia adalah. Pembina adalah benar-benar kaedah, tetapi dengan ciri khusus :) Sama seperti kaedah, kami menyerahkan hujah kepada pembina kami. Dan sama seperti memanggil kaedah, memanggil pembina tidak akan berfungsi melainkan anda menentukannya:

public class Car {

   String model;
   int maxSpeed;

   public Car(String model, int maxSpeed) {
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   public static void main(String[] args) {
       Car bugatti = new Car(); // Error!
   }
  
}
Anda boleh melihat bahawa pembina mencapai apa yang kami cuba capai. Kini anda tidak boleh mencipta kereta tanpa kelajuan atau model! Persamaan antara pembina dan kaedah tidak berakhir di sini. Sama seperti kaedah, pembina boleh dibebankan. Bayangkan anda mempunyai 2 ekor kucing peliharaan di rumah. Anda mendapat salah seorang daripada mereka sebagai anak kucing. Tetapi yang kedua yang anda ambil dari jalan apabila ia sudah dewasa, dan anda tidak tahu berapa umurnya. Dalam kes ini, kami mahu program kami dapat mencipta dua jenis kucing: kucing yang mempunyai nama dan umur (untuk kucing pertama), dan kucing yang hanya mempunyai nama (untuk kucing kedua). Untuk ini, kami akan membebankan pembina:

public class Cat {

   String name;
   int age;

   // For the first cat
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   // For the second cat
   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5);
       Cat streetCatNamedBob = new Cat("Bob");
   }

}
Sebagai tambahan kepada pembina asal dengan parameter "nama" dan "umur", kami menambah satu lagi dengan hanya parameter nama. Dengan cara yang sama seperti kami membebankan kaedah dalam pelajaran sebelumnya. Sekarang kita boleh mencipta kedua-dua jenis kucing :)
Mengapa kita memerlukan pembina?  - 2
Ingat bahawa pada permulaan pelajaran kami mengatakan bahawa anda telah menggunakan pembina tanpa menyedarinya? Kami maksudkan apa yang kami katakan. Hakikatnya ialah setiap kelas di Java mempunyai apa yang dipanggil pembina lalai. Ia tidak memerlukan sebarang hujah, tetapi ia digunakan setiap kali anda mencipta sebarang objek dari mana-mana kelas.

public class Cat {

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
Pada pandangan pertama, ia tidak kelihatan. Kami mencipta objek, jadi apa? Di manakah pembina melakukan apa-apa di sini? Untuk melihatnya, mari tulis pembina kosong untuk kelas Cat secara eksplisit . Kami akan memaparkan beberapa frasa di dalamnya. Jika frasa dipaparkan, maka pembina telah dipanggil.

public class Cat {

   public Cat() {
       System.out.println("A cat has been created!");
   }

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
Output konsol: Kucing telah dibuat! Ada pengesahan! Pembina lalai sentiasa tidak kelihatan dalam kelas anda. Tetapi anda perlu tahu satu lagi perkara mengenainya. Pembina lalai dihapuskan daripada kelas sebaik sahaja anda mencipta pembina dengan hujah. Malah, kita telah melihat bukti ini di atas. Ia berada dalam kod ini:

public class Cat {

   String name;
   int age;

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

   public static void main(String[] args) {

       Cat smudge = new Cat(); //Error!
   }
}
Kami tidak boleh mencipta Cat tanpa nama dan umur, kerana kami mengisytiharkan pembina Cat dengan parameter rentetan dan int . Ini menyebabkan pembina lalai segera hilang dari kelas. Jadi pastikan anda ingat bahawa jika anda memerlukan beberapa pembina dalam kelas anda, termasuk pembina tanpa hujah, anda perlu mengisytiharkannya secara berasingan. Sebagai contoh, katakan kita sedang membuat program untuk klinik veterinar. Klinik kami ingin beramal dan membantu anak kucing gelandangan yang tidak diketahui namanya dan umur. Kemudian kod kami sepatutnya kelihatan seperti ini:

public class Cat {

   String name;
   int age;

   // For cats with owners
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   // For street cats
   public Cat() {
   }

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5);
       Cat streetCat = new Cat();
   }
}
Memandangkan kita telah menulis pembina lalai yang jelas, kita boleh mencipta kedua-dua jenis kucing :) Seperti mana-mana kaedah, susunan hujah yang dihantar kepada pembina adalah sangat penting. Mari kita tukar nama dan hujah umur dalam pembina kami.

public class Cat {

   String name;
   int age;

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

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 10); // Error!
   }
}
Kesilapan! Pembina dengan jelas menetapkan bahawa apabila objek Cat dicipta, ia mesti diluluskan nombor dan rentetan, dalam susunan ini. Jadi, kod kami tidak berfungsi. Pastikan anda mengingati perkara ini dan mengingatinya apabila mengisytiharkan kelas anda sendiri:

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

public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
Ini adalah dua pembina yang sama sekali berbeza! Jika kita menyatakan dalam satu ayat jawapan kepada soalan "Mengapa saya memerlukan pembina?", kita mungkin berkata, "Untuk memastikan objek sentiasa mempunyai keadaan yang sah". Apabila anda menggunakan pembina, semua pembolehubah anda akan dimulakan dengan betul. Program anda tidak akan mempunyai sebarang kereta dengan kelajuan 0 atau mana-mana objek "tidak sah" lain. Faedah utama mereka adalah untuk pengaturcara. Jika anda memulakan medan secara manual (selepas mencipta objek), terdapat risiko besar anda akan terlepas sesuatu dan memperkenalkan pepijat. Tetapi ini tidak akan berlaku dengan pembina: jika anda gagal lulus semua hujah yang diperlukan atau anda lulus jenis hujah yang salah, pengkompil akan segera mendaftarkan ralat. Kami juga mesti secara berasingan mengatakan bahawa anda tidak sepatutnya meletakkan program anda' s logik di dalam pembina. Inilah gunanya kaedah. Kaedah adalah tempat anda harus menentukan semua fungsi yang diperlukan. Mari lihat mengapa menambah logik kepada pembina adalah idea yang tidak baik:

public class CarFactory {

   String name;
   int age;
   int carsCount;

   public CarFactory(String name, int age, int carsCount) {
   this.name = name;
   this.age = age;
   this.carsCount = carsCount;

   System.out.println("Our car factory is called " + this.name);
   System.out.println("It was founded " + this.age + " years ago" );
   System.out.println("Since that time, it has produced " + this.carsCount +  " cars");
   System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
}

   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Ford", 115 , 50000000);
   }
}
Kami mempunyai kelas CarFactory yang menerangkan tentang kilang kereta. Di dalam pembina, kami memulakan semua medan dan memasukkan beberapa logik: kami memaparkan beberapa maklumat tentang kilang. Nampaknya tidak ada yang buruk tentang ini. Program ini berfungsi dengan baik. Keluaran konsol: Kilang kereta kami dipanggil Ford Ia diasaskan 115 tahun yang lalu Sejak masa itu, ia telah menghasilkan 50000000 kereta Secara purata, ia menghasilkan 434782 kereta setahun Tetapi kami sebenarnya telah meletakkan lombong yang tertunda masa. Dan kod semacam ini boleh membawa kepada ralat dengan mudah. Katakan sekarang kita bercakap bukan tentang Ford, tetapi tentang kilang baru yang dipanggil "Amigo Motors", yang telah wujud kurang dari setahun dan telah menghasilkan 1000 kereta:

public class CarFactory {

   String name;
   int age;
   int carsCount;

   public CarFactory(String name, int age, int carsCount) {
   this.name = name;
   this.age = age;
   this.carsCount = carsCount;

   System.out.println("Our car factor is called " + this.name);
   System.out.println("It was founded " + this.age + " years ago" );
   System.out.println("Since that time, it has produced " + this.carsCount +  " cars");
   System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
}


   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Amigo Motors", 0 , 1000);
   }
}
Keluaran konsol: Kilang kereta kami dipanggil Amigo Motors Exception dalam benang "utama" java.lang.ArithmeticException: / by zero Ia diasaskan 0 tahun yang lalu Sejak itu, ia telah mengeluarkan 1000 kereta di CarFactory. (CarFactory.java:15) di CarFactory.main(CarFactory.java:23) Proses selesai dengan kod keluar 1 Boom! Program ini berakhir dengan beberapa jenis ralat yang tidak dapat difahami. Bolehkah anda cuba meneka puncanya? Masalahnya adalah dalam logik yang kita masukkan ke dalam pembina. Lebih khusus lagi, baris ini:

System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
Di sini anda sedang melakukan pengiraan dan membahagikan bilangan kereta yang dihasilkan mengikut umur kilang. Dan kerana kilang kami baru (iaitu 0 tahun), kami bahagikan dengan 0, yang tidak boleh kami lakukan dalam matematik. Akibatnya, program ditamatkan dengan ralat.

Apa yang sepatutnya kita lakukan?

Letakkan semua logik dalam kaedah yang berasingan. Mari kita panggil printFactoryInfo() . Anda boleh menghantar objek CarFactory kepadanya sebagai hujah. Anda boleh meletakkan semua logik di sana, dan pada masa yang sama mengendalikan kemungkinan ralat (seperti kami yang melibatkan sifar tahun). Kepada masing-masing miliknya. Pembina diperlukan untuk menetapkan keadaan objek yang sah. Kami mempunyai kaedah untuk logik perniagaan. Jangan campur satu dengan yang lain. Untuk mengukuhkan perkara yang anda pelajari, kami cadangkan anda menonton pelajaran video daripada Kursus Java kami
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION