JavaRush /Blog Java /Random-VI /Trình xây dựng trong Java

Trình xây dựng trong Java

Xuất bản trong nhóm
Xin chào! Hôm nay chúng ta sẽ xem xét một chủ đề rất quan trọng liên quan đến đối tượng của chúng ta. Ở đây, không hề cường điệu, chúng tôi có thể nói rằng bạn sẽ sử dụng kiến ​​thức này hàng ngày trong công việc thực tế! Chúng ta sẽ nói về các nhà xây dựng. Có thể bạn mới nghe thấy thuật ngữ này lần đầu tiên, nhưng trên thực tế, có thể bạn đã sử dụng hàm tạo, nhưng chính bạn lại không nhận thấy nó :) Chúng ta sẽ thấy điều này sau.

Hàm tạo trong Java là gì và tại sao nó lại cần thiết?

Hãy xem xét hai ví dụ.
public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

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

   }
}
Chúng tôi đã tạo ra chiếc xe của mình và thiết lập kiểu dáng cũng như tốc độ tối đa của nó. Tuy nhiên, trong một dự án thực tế, đối tượng Ô tô rõ ràng sẽ có nhiều hơn 2 trường. Và, ví dụ, 16 lĩnh vực!
public class Car {

   String model;//model
   int maxSpeed;//max speed
   int wheels;// disk width
   double engineVolume;//engine capacity
   String color;//color
   int yearOfIssue;//year of issue
   String ownerFirstName;//Owner's name
   String ownerLastName;//owner's last name
   long price;//price
   boolean isNew;//new or not
   int placesInTheSalon;//number of seats in the cabin
   String salonMaterial;// interior material
   boolean insurance;//is it insured
   String manufacturerCountry;//manufacturer country
   int trunkVolume;// trunk volume
   int accelerationTo100km;//acceleration 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.yearOfIssue = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.placesInTheSalon = 2;
       bugatti.maxSpeed = 407;
       bugatti.model = "Bugatti Veyron";

   }

}
Chúng ta đã tạo một đối tượng Car mới . Một vấn đề: chúng tôi có 16 trường nhưng chúng tôi chỉ khởi tạo 12 trường ! Hãy thử sử dụng mã ngay bây giờ để tìm những mã mà chúng tôi đã quên! Không dễ dàng như vậy phải không? Trong tình huống như vậy, người lập trình có thể dễ dàng mắc lỗi và bỏ qua việc khởi tạo một trường nào đó. Kết quả là hoạt động của chương trình sẽ trở nên sai lầm:
public class Car {

   String model;//model
   int maxSpeed;//max speed
   int wheels;// disk width
   double engineVolume;//engine capacity
   String color;//color
   int yearOfIssue;//year of issue
   String ownerFirstName;//Owner's name
   String ownerLastName;//owner's last name
   long price;//price
   boolean isNew;//new or not
   int placesInTheSalon;//number of seats in the cabin
   String salonMaterial;// interior material
   boolean insurance;//is it insured
   String manufacturerCountry;//manufacturer country
   int trunkVolume;// trunk volume
   int accelerationTo100km;//acceleration 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.yearOfIssue = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.placesInTheSalon = 2;
       bugatti.maxSpeed = 407;
       bugatti.model = "Bugatti Veyron";

       System.out.println("Model Bugatti Veyron. Engine size - " + bugatti.engineVolume + ", trunk - " + bugatti.trunkVolume + ", salon is made of" + bugatti.salonMaterial +
       ", disc width - " + bugatti.wheels + ". Was acquired in 2018 by Mr. " + bugatti.ownerLastName);

   }

}
Đầu ra của bảng điều khiển:
Mẫu Bugatti Veyron. Dung tích động cơ - 6,3, cốp - 0, nội thất rỗng, chiều rộng vành - 0. Được ông null mua vào năm 2018
Người mua của bạn, người đã trả 2 triệu USD cho một chiếc ô tô, rõ ràng sẽ không thích bị gọi là “Ông Null”! Nhưng nghiêm túc mà nói, cuối cùng, chương trình của chúng tôi đã kết thúc với một đối tượng được tạo không chính xác - một chiếc ô tô có chiều rộng vành 0 (nghĩa là không có vành nào cả), một cốp xe bị thiếu, nội thất làm bằng vật liệu không xác định và thậm chí thuộc về một người không xác định . Người ta chỉ có thể tưởng tượng làm thế nào một lỗi như vậy có thể xảy ra khi chương trình đang chạy! Chúng ta cần bằng cách nào đó tránh những tình huống như vậy. Chúng ta cần chương trình của mình có một giới hạn: chẳng hạn như khi tạo một đối tượng phương tiện mới, mẫu và tốc độ tối đa phải luôn được chỉ định cho nó. Nếu không, không cho phép tạo đối tượng. Các hàm xây dựng dễ dàng đối phó với nhiệm vụ này. Họ có tên của họ vì một lý do. Hàm tạo tạo ra một loại “bộ khung” của lớp mà mỗi đối tượng mới của lớp phải tương ứng với nó. Để thuận tiện, chúng ta hãy quay lại phiên bản đơn giản hơn của lớp Xe hơi với hai trường. Dựa trên yêu cầu của chúng tôi, hàm tạo của lớp Car sẽ trông như thế này:
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
Và việc tạo một đối tượng bây giờ trông như thế này:
public static void main(String[] args) {
   Car bugatti = new Car("Bugatti Veyron", 407);
}
Chú ýcách tạo ra hàm tạo. Nó tương tự như một phương thức thông thường nhưng không có kiểu trả về. Trong trường hợp này, tên lớp được chỉ định trong hàm tạo, cũng bằng chữ in hoa. Trong trường hợp của chúng tôi - Ô tô . Ngoài ra, hàm tạo còn sử dụng từ khóa mới cho bạn this . “this” trong tiếng Anh có nghĩa là “cái này, cái này”. Từ này đề cập đến một đối tượng cụ thể. Mã trong hàm tạo:
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
có thể dịch gần như theo nghĩa đen: " mô hình cho máy này (mà chúng tôi hiện đang tạo) = đối số mô hình , được chỉ định trong hàm tạo. maxSpeed ​​​​cho máy này (mà chúng tôi đang tạo) = đối số maxSpeed , mà được chỉ định trong hàm tạo." Đây là những gì đã xảy ra:
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", 407);
       System.out.println(bugatti.model);
       System.out.println(bugatti.maxSpeed);
   }

}
Đầu ra của bảng điều khiển:
Bugatti Veyron 407
Hàm tạo đã gán thành công các giá trị được yêu cầu. Bạn có thể nhận thấy rằng hàm tạo rất giống với một phương thức thông thường! Nó là thế này: hàm tạo là một phương thức, chỉ cụ thể một chút thôi :) Cũng giống như trong một phương thức, chúng ta truyền tham số cho hàm tạo của mình. Và cũng giống như gọi một phương thức, việc gọi hàm tạo sẽ không hoạt động nếu bạn không chỉ định chúng:
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!
   }

}
Bạn thấy đấy, nhà thiết kế đã làm được điều mà chúng tôi đang cố gắng đạt được. Bây giờ bạn không thể tạo ra một chiếc ô tô không có tốc độ hoặc không có mô hình! Sự tương đồng giữa hàm tạo và phương thức không dừng lại ở đó. Cũng giống như các phương thức, hàm tạo có thể bị quá tải. Hãy tưởng tượng rằng bạn có 2 con mèo ở nhà. Bạn đã nuôi một trong số chúng khi còn là một chú mèo con và bạn mang con thứ hai từ ngoài đường về nhà khi trưởng thành và bạn không biết chính xác nó bao nhiêu tuổi. Điều này có nghĩa là chương trình của chúng ta có thể tạo ra hai loại mèo - có tên và tuổi cho con mèo đầu tiên và chỉ có tên - cho con mèo thứ hai. Để làm điều này, chúng ta sẽ nạp chồng hàm tạo:
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 barsik = new Cat("Barsik", 5);
       Cat streetCatNamedBob = new Cat("Bob");
   }

}
Đối với hàm tạo ban đầu có tham số “name” và “age”, chúng tôi đã thêm một tham số khác, chỉ với một tên. Chúng ta đã nạp chồng các phương thức theo cách tương tự trong các bài học trước. Bây giờ chúng ta có thể tạo thành công cả hai phiên bản của mèo :) Tại sao cần có constructor?  - 2Bạn có nhớ ở đầu bài giảng chúng ta đã nói rằng bạn đã sử dụng hàm tạo nhưng bạn không nhận thấy điều đó không? Điều này là đúng. Thực tế là mọi lớp trong Java đều có cái gọi là hàm tạo mặc định. Nó không có bất kỳ đối số nào, nhưng nó kích hoạt mỗi khi bất kỳ đối tượng nào của bất kỳ lớp nào được tạo.
public class Cat {

   public static void main(String[] args) {

       Cat barsik = new Cat(); //this is where the default constructor worked
   }
}
Thoạt nhìn điều này không đáng chú ý. Chà, chúng ta đã tạo ra một vật thể và tạo ra nó, công việc của người thiết kế ở đâu? Để thấy điều này, chúng ta hãy tự tay viết một hàm tạo trống cho lớp Cat và bên trong nó, chúng ta sẽ in một số cụm từ ra bảng điều khiển. Nếu nó được hiển thị thì hàm tạo đã hoạt động.
public class Cat {

   public Cat() {
       System.out.println("Created a cat!");
   }

   public static void main(String[] args) {

       Cat barsik = new Cat(); //this is where the default constructor worked
   }
}
Đầu ra của bảng điều khiển:
Họ đã tạo ra một con mèo!
Đây là sự xác nhận! Hàm tạo mặc định luôn hiện diện vô hình trong các lớp của bạn. Nhưng bạn cần biết thêm một tính năng nữa của nó. Hàm tạo mặc định sẽ biến mất khỏi lớp khi bạn tạo một số hàm tạo có đối số. Bằng chứng về điều này, trên thực tế, chúng ta đã thấy ở trên. Ở đây trong mã này:
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 barsik = new Cat(); //error!
   }
}
Chúng tôi không thể tạo một con mèo mà không có tên và tuổi vì chúng tôi đã xác định hàm tạo cho Cat : chuỗi + số. Hàm tạo mặc định đã biến mất khỏi lớp ngay sau đó. Do đó, hãy nhớ nhớ: nếu bạn cần một số hàm tạo trong lớp của mình, bao gồm cả một hàm tạo trống, bạn cần phải tạo nó một cách riêng biệt. Ví dụ: chúng tôi đang tạo một chương trình cho một phòng khám thú y. Phòng khám của chúng tôi muốn làm những việc tốt và giúp đỡ những chú mèo vô gia cư mà chúng tôi không biết tên và tuổi của chúng. Sau đó, mã của chúng ta sẽ trông như thế này:
public class Cat {

   String name;
   int age;

   //for domestic cats
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   //for street cats
   public Cat() {
   }

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5);
       Cat streetCat = new Cat();
   }
}
Bây giờ chúng ta đã viết rõ ràng một hàm tạo mặc định, chúng ta có thể tạo ra cả hai loại mèo :) Đối với một hàm tạo (như đối với bất kỳ phương thức nào), thứ tự của các đối số là rất quan trọng. Hãy hoán đổi các đối số tên và tuổi trong hàm tạo của chúng ta.
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 barsik = new Cat("Barsik", 10); //error!
   }
}
Lỗi! Hàm tạo nêu rõ rằng khi một đối tượng Cat được tạo, nó phải được truyền một số và một chuỗi theo thứ tự đó. Đó là lý do tại sao mã của chúng tôi không hoạt động. Hãy nhớ ghi nhớ điều này khi tạo các lớp của riêng bạn:
public Cat(String name, int age) {
   this.name = name;
   this.age = age;
}

public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
Đây là hai nhà thiết kế hoàn toàn khác nhau! Nếu chúng ta diễn đạt câu trả lời cho câu hỏi “Tại sao chúng ta cần một hàm tạo?” trong một câu, chúng ta có thể nói: để các đối tượng luôn ở trạng thái chính xác. Khi bạn sử dụng hàm tạo, tất cả các biến của bạn sẽ được khởi tạo chính xác và sẽ không có ô tô nào có tốc độ 0 hoặc các đối tượng “không chính xác” khác trong chương trình. Việc sử dụng chúng trước hết rất có lợi cho bản thân người lập trình viên. Nếu bạn tự khởi tạo các trường, sẽ có nguy cơ cao bị thiếu thứ gì đó và mắc lỗi. Nhưng điều này sẽ không xảy ra với một hàm tạo: nếu bạn không chuyển tất cả các đối số cần thiết cho nó hoặc trộn lẫn các kiểu của chúng, trình biên dịch sẽ ngay lập tức đưa ra lỗi. Điều đáng nói riêng là bạn không nên đặt logic của chương trình bên trong hàm tạo. Để làm điều này, bạn có sẵn các phương pháp để có thể mô tả tất cả chức năng bạn cần. Hãy xem tại sao logic xây dựng lại là một ý tưởng tồi:
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("She was founded" + this.age + " years ago" );
   System.out.println("During this time it was produced" + this.carsCount +  "cars");
   System.out.println("On average she produces" + (this.carsCount/this.age) + "cars per year");
}

   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Ford", 115 , 50000000);
   }
}
Chúng ta có một lớp CarFactory mô tả một nhà máy sản xuất ô tô. Bên trong hàm tạo, chúng tôi khởi tạo tất cả các trường và đặt logic ở đây: chúng tôi hiển thị một số thông tin về nhà máy trên bảng điều khiển. Có vẻ như điều này không có gì sai, chương trình đã hoạt động hoàn hảo. Đầu ra của bảng điều khiển:
Nhà máy sản xuất ô tô của chúng tôi tên là Ford, được thành lập cách đây 115 năm, trong thời gian này đã sản xuất được 50.000.000 ô tô, trung bình mỗi năm sản xuất được 434.782 ô tô.
Nhưng thực tế là chúng ta đã đặt một quả bom hẹn giờ. Và mã như vậy rất dễ dẫn đến lỗi. Hãy tưởng tượng rằng bây giờ chúng ta không nói về Ford mà là về nhà máy mới "Amigo Motors", mới tồn tại chưa đầy một năm và đã sản xuất 1000 chiếc ô tô:
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("She was founded" + this.age + " years ago" );
   System.out.println("During this time it was produced" + this.carsCount +  "cars");
   System.out.println("On average she produces" + (this.carsCount/this.age) + "cars per year");
}


   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Amigo Motors", 0 , 1000);
   }
}
Đầu ra của bảng điều khiển:
Nhà máy ô tô của chúng tôi có tên là Amigo Motors Exception trong chủ đề "main" java.lang.ArithmeticException: / by zero Nó được thành lập 0 năm trước. Trong thời gian này, nó đã sản xuất 1000 ô tô tại CarFactory.<init>(CarFactory.java:15) tại CarFactory.main(CarFactory.java:23) Quá trình đã hoàn tất với mã thoát 1</init>
Chúng tôi đã đến nơi! Chương trình kết thúc với một số lỗi lạ. Bạn thử đoán xem lý do là gì? Lý do là logic chúng tôi đặt trong hàm tạo. Cụ thể ở dòng này:
System.out.println("On average she produces" + (this.carsCount/this.age) + "cars per year");
Ở đây chúng tôi thực hiện tính toán và chia số lượng ô tô sản xuất theo tuổi của nhà máy. Và vì nhà máy của chúng tôi là mới (tức là đã 0 năm tuổi) nên kết quả là chia cho 0, điều này bị cấm trong toán học. Kết quả là chương trình kết thúc với một lỗi. Đáng lẽ chúng ta phải làm gì? Di chuyển tất cả logic vào một phương thức riêng biệt và gọi nó, ví dụ: printFactoryInfo() . Bạn có thể truyền cho nó một đối tượng CarFactory làm tham số . Bạn cũng có thể đặt tất cả logic vào đó, đồng thời - xử lý các lỗi có thể xảy ra, giống như lỗi của chúng tôi với 0 năm. Của riêng mình. Các nhà xây dựng là cần thiết để thiết lập chính xác trạng thái của một đối tượng. Đối với logic nghiệp vụ, chúng ta có các phương thức. Bạn không nên trộn lẫn cái này với cái kia.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION