Tại sao không có hàm tạo mặc định được tạo nếu bạn xác định hàm tạo rõ ràng?


9
class Employee{

    String name;
    int id;

   //No explicit constructors
}

Bây giờ tôi có thể gọi câu lệnh sau:

Employee e1 = new Employee();

Với đoạn mã trên, trình biên dịch sẽ cung cấp định nghĩa cho hàm tạo Employee().

Nếu tôi định nghĩa một hàm tạo rõ ràng như sau:

 class Employee{

    String name;
    int id;

    Employee(String aName){
        this.name=aName;
    }
}

Bây giờ, tại sao tôi không thể gọi câu sau:

Employee e2 = new Employee();

Mặc dù trình biên dịch biết cách cung cấp định nghĩa Employee().

Bây giờ, chỉ vì tôi đã xác định một hàm tạo rõ ràng Employee(String aName), tại sao tôi không thể sử dụng một hàm tạo mặc định?

Ngoài ra, nếu trình biên dịch đã cho phép sử dụng hàm tạo mặc định ngay cả sau khi xác định hàm rõ ràng, nó sẽ giúp chúng ta sử dụng lại mã cho hàm tạo mặc định.


7
Nó sẽ không còn là một constructor mặc định nữa. Tôi sẽ là một nhà xây dựng liên tục bởi vì nó luôn ở đó.
Phản ứng

Câu trả lời:


6

Trước hết, hàm tạo mặc định không được tạo, nó được trình biên dịch cung cấp nếu hàm tạo không có đối số không được viết rõ ràng.

Khi bạn không viết rõ ràng một hàm tạo không có đối số cho một lớp, trình biên dịch sẽ không phàn nàn miễn là các đối tượng được xây dựng mà không có các hàm tạo tham số. (Vì trình biên dịch cho phép hàm tạo mặc định tạo các đối tượng, chính nó gọi lệnh cho hàm tạo không có đối số ).

Nhưng nếu bạn định nghĩa một hàm tạo không có đối số, khi biên dịch, trình biên dịch sẽ kiểm tra lệnh gọi đến hàm tạo và định nghĩa của nó trong lớp. Nó giống như xác thực bất kỳ phương thức nào khác của một lớp.

Vì vậy, nó sẽ báo lỗi nếu bạn gọi hàm tạo không có đối số sau khi xác định hàm tạo được tham số hóa, vì nó tìm thấy hàm tạo không có đối số được xác định rõ ràng trong lớp. Và, điều này là hợp lý vì, nếu bạn muốn chặn việc tạo các đối tượng mà không có bất kỳ dữ liệu nào trong đó, đây là một cách tốt.

Ví dụ, hãy xem xét rằng một đối tượng nhân viên phải có id nhân viên liên quan đến nó. Để đạt được điều này, hãy xác định một hàm tạo đối số duy nhất và không xác định hàm tạo không có đối số.


39

Một constructor với các đối số không chỉ là một tốc ký tiện dụng để sử dụng setters. Bạn viết một hàm tạo để đảm bảo rằng một đối tượng sẽ không bao giờ tồn tại mà không có dữ liệu nhất định.

Nếu không có yêu cầu như vậy, tốt. Nhưng nếu có một cái, như được chỉ ra bởi thực tế là bạn đã viết một hàm tạo như vậy, thì việc tạo một hàm tạo mặc định là vô trách nhiệm, qua đó khách hàng có thể phá vỡ quy tắc "không có đối tượng không có dữ liệu". Chắc chắn là như vậy, bởi vì hàm tạo mặc định được tạo tự động là vô hình đối với trình đọc mã thông thường, nó che giấu thực tế rằng nó tồn tại! Không, nếu bạn muốn các hàm tạo có đối số hàm tạo mặc định, bạn phải tự viết hàm tạo mặc định. Dù sao, nó không phải là rất nhiều nỗ lực để viết một khối trống.


4
nói tốt, nếu tôi viết một hàm tạo với các tham số, thì đó là vì các giá trị đó là cần thiết cho các thể hiện của lớp hoạt động. Nếu tôi có một số giá trị mặc định hữu ích, tôi sẽ viết một hàm tạo không có đối số gọi hàm tạo khác trong khi cung cấp các giá trị mặc định đó.
jwenting

+1. Ngoài ra, nếu bạn không thể đảm bảo rằng các trường sẽ được khởi tạo trong hàm tạo, bạn không bao giờ có thể có các đối tượng bất biến, đó là điều bạn nên thích.
Doval

2
@Doval: mà bạn nên thích, trong những tình huống nhất định. Giống như mọi thứ khác, các đối tượng bất biến có sự đánh đổi làm cho chúng tốt cho một số tình huống và không phải cho những người khác. Không có viên đạn bạc.
tên của

1
@whatsisname Không bao giờ gọi nó là viên đạn bạc, nhưng nó là mặc định tốt hơn.
Doval

Câu trả lời này rất hữu ích để đọc cùng với Câu trả lời cũng hay của Konrad Morawski: Câu trả lời của ông cung cấp một sự tương tự trong thế giới thực tốt đẹp để giải thích về cơ bản cùng một câu trả lời.
cellepo

8

Java tạo ra một hàm tạo không tham số khi bạn không có bất kỳ hàm nào khác giống như một người phục vụ lịch sự lấy áo khoác cho bạn.

Java vẫn tạo ra một hàm tạo không tham số sau khi bạn định nghĩa một phiên bản khác của nó giống như người phục vụ cởi áo khoác cho bạn sau khi bạn đưa ra một dấu hiệu rõ ràng rằng bạn có kế hoạch riêng của mình về việc phải làm gì với lớp phủ.

Nếu tôi có một lớp học (mà tôi muốn trở thành bất biến):

class Person
{
    final String firstName;
    final String lastName;

Và tôi thêm một hàm tạo:

    Person(String firstName, String lastName) 
    {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

Và Java vẫn cung cấp một hàm tạo không tham số mặc định, sau đó mã này không thể biên dịch được, bởi vì firstNamelastNamecác trường được khai báo là cuối cùng, nhưng chúng không được đặt sau khi bạn gọi Person p = new Person().

Bạn đang buộc tôi cung cấp một triển khai khác:

private Person() 
{
    this.firstName = null; // or "", or whatever
    this.lastName = null;
}

Và vì tôi không muốn nó - vì nó vô dụng, tôi có thể cảm thấy có xu hướng đặt hộp sọ và xương chéo lên nó:

@Deprecated
private Person() 
{
    // don't use this constructor! i don't want it to ever be called!
    throw new RuntimeException("Illegal constructor called");
}

Nhưng tôi vẫn không thể cấm một nhà phát triển khác tạo một phương thức (bên trong Personlớp, vì vậy việc đánh dấu hàm tạo là riêng tư không giúp ích gì):

public static Person createPerson()
{
    return new Person(); // this will blow in our face
}

Tất cả sự phiền phức này có thể - và - được tránh nhờ vào việc Java (và không chỉ Java) hoạt động theo cách nó hoạt động.

Nếu bạn xác định một phương thức setCoordinates(int x, int y), bạn không mong muốn trình biên dịch tự động chấp nhận một phiên bản không tham số của phương thức đó - setCoordinates(). Nó sẽ không làm một điều gì.

Làm thế nào khác với mong đợi một nhà xây dựng không tham số? Chà, rõ ràng, một nhà xây dựng luôn làm ít nhất một điều - nó tạo ra một đối tượng (hoặc chết khi cố gắng).

Nhưng tôi thích được kiểm soát cách tôi muốn các đối tượng của mình được khởi tạo. Buộc tôi phải có một hàm tạo không tham số cho dù tôi có làm gì đi điều khiển này khỏi tôi.


Câu trả lời này rất hữu ích để đọc cùng với Câu trả lời cũng hay của Kilian Foth. Tôi yêu sự sáng tạo của người phục vụ / giải thích áo / tương tự, đó là hợp lệ và hoạt động!
cellepo

3

Ngôn ngữ đặt nhà xây dựng mặc định là một lợi ích cho bạn. Giả định là nếu bạn đã viết một hàm tạo tùy chỉnh, hàm tạo không có đối số của bạn cũng có thể yêu cầu sự chú ý đặc biệt. Không phải là một lý do tuyệt vời, nhưng cũng không phải là khủng khiếp.

Id lý do thứ cấp mà cruft chỉ chồng chất lên ngôn ngữ đó mà không cần suy nghĩ về tính đối xứng của nó với thực tiễn hiện có và rất ít quan tâm đến việc làm cho nó có thể đọc được. "C with Classes" ban đầu của Stoustroup là một bộ tiền xử lý C đã bị hack mà có lẽ không nên đưa nó ra khỏi phòng thí nghiệm. Thế giới buồn cười theo cách đó.


3

Nếu bạn xác định một hàm tạo với một tham số, thì phải có một lý do hợp lệ để làm như vậy. Có thể tham số này rất quan trọng đối với lớp của bạn mà không có nó thì trạng thái đối tượng không hợp lệ. Đó là lý do tại sao Java không tạo ra một hàm tạo không có đối số cho bạn khi bạn đã định nghĩa nó.

Nếu bạn quyết định rằng sẽ có ích khi có hàm tạo không có đối số, thì bạn vẫn có thể định nghĩa nó:

Employee(){
  // good practice to call existing constructor with your favorite value
  this("");
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.