Menu

Constructor trong Java: khởi tạo đối tượng với new

Cách hàm khởi tạo trong Java hoạt động: hàm khởi tạo mặc định, hàm khởi tạo có tham số, this, nạp chồng constructor và gọi nối bằng this() và super().

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Vì sao cần constructor

Ở trang trước, bạn đã tạo lớp và tạo đối tượng bằng new. Hàm khởi tạo (constructor) chính là đoạn code thực sự chạy trong lời gọi new đó. Nó chỉ có một mục đích: trả về một đối tượng sẵn sàng để dùng, mọi thuộc tính bắt buộc đã được gán, không có trạng thái khởi tạo dở dang.

Constructor trông giống một phương thức, với hai điểm khác: nó có cùng tên với lớp và không có kiểu trả về, kể cả void.

new Point(3, 4) cấp phát đối tượng rồi chạy thân constructor với x = 3 và y = 4. Khi new trả về, p đã được khởi tạo đầy đủ.

Từ khóa this

Trong constructor ở trên, các tham số tên là x và y, trùng với tên thuộc tính. this.x nghĩa là "thuộc tính x của chính đối tượng này", còn x đơn thuần là tham số. Nếu không có this, x = x chỉ gán tham số cho chính nó và để nguyên thuộc tính.

Bạn chỉ cần this khi tham số che khuất (shadow) một thuộc tính, nhưng nhiều người dùng nó ở mọi chỗ cho rõ ràng. Lỗi thường gặp là quên this khi tên bị trùng: code vẫn biên dịch, vẫn chạy, và lặng lẽ để các thuộc tính ở giá trị mặc định (null, 0, false).

Constructor mặc định

Nếu bạn không viết constructor nào, Java tự cung cấp một constructor mặc định: một constructor public, không tham số và không làm thêm gì. Đó là lý do new vẫn chạy được với những lớp hoàn toàn không có constructor.

Điểm cần lưu ý: ngay khi bạn viết bất kỳ constructor nào, constructor miễn phí kia không còn nữa.

class Box {
    int size;

    Box(int size) {       // now there is NO no-arg constructor
        this.size = size;
    }
}

new Box();   // compile error: no constructor Box() exists

Nếu vẫn muốn new Box() hoạt động, hãy tự khai báo constructor không tham số:

Nạp chồng constructor

Một lớp có thể có nhiều constructor, miễn là danh sách tham số khác nhau. Đây chính là nạp chồng phương thức (method overloading) áp dụng cho constructor. Mỗi constructor cho bạn một cách khác để tạo đối tượng.

Java chọn constructor phù hợp dựa trên số lượng và kiểu của các đối số bạn truyền vào new.

Gọi nối bằng this()

Hãy để ý sự lặp lại ở trên: constructor nào cũng tự gán thuộc tính. Bạn có thể tránh điều đó bằng cách cho một constructor gọi constructor khác qua this(...). Lời gọi này phải là câu lệnh đầu tiên trong constructor.

Giờ phần khởi tạo thực sự chỉ nằm ở một chỗ. Các constructor nhỏ hơn chỉ điền giá trị mặc định rồi chuyển việc tiếp. Nếu bạn đặt một câu lệnh trước this(...), trình biên dịch sẽ báo lỗi.

Constructor và super()

Mọi constructor đều ngầm gọi constructor của lớp cha trước tiên. Nếu bạn không viết gì, Java chèn một lời gọi super() ẩn (constructor không tham số của lớp cha) vào đầu thân hàm. Bạn sẽ làm việc trực tiếp với nó khi bắt đầu tạo lớp con, cũng là chủ đề tiếp theo.

class Animal {
    String name;
    Animal(String name) { this.name = name; }
}

class Dog extends Animal {
    Dog(String name) {
        super(name);   // must call the parent constructor explicitly here
    }
}

Vì Animal không có constructor không tham số, Dog bắt buộc phải gọi super(name) một cách tường minh: không có super() miễn phí nào để dựa vào. Giống this(), lời gọi super(...) phải là câu lệnh đầu tiên trong constructor.

Tiếp theo: kế thừa

Constructor khởi tạo một đối tượng, nhưng super() đã hé lộ một điều lớn hơn: lớp có thể được xây dựng dựa trên lớp khác, dùng lại thuộc tính, phương thức và constructor của lớp đó. Mối quan hệ này, một lớp mở rộng (extends) lớp khác, gọi là kế thừa (inheritance), và đó là nội dung của trang tiếp theo.

Câu hỏi thường gặp

Constructor trong Java là gì?

Constructor (hàm khởi tạo) là một phương thức đặc biệt chạy khi bạn tạo đối tượng bằng new. Nó có cùng tên với lớp và không có kiểu trả về (kể cả void). Nhiệm vụ của nó là đưa đối tượng mới vào một trạng thái ban đầu hợp lệ, thường bằng cách gán các đối số nhận được cho các thuộc tính của đối tượng.

Constructor và phương thức trong Java khác nhau thế nào?

Constructor có tên giống hệt tên lớp, không khai báo kiểu trả về và chỉ được gọi bằng new khi tạo đối tượng. Phương thức thông thường có tên riêng, khai báo kiểu trả về (hoặc void) và được gọi trên một đối tượng đã tồn tại. Constructor lo việc khởi tạo; phương thức làm việc sau đó.

Nếu không viết constructor trong Java thì chuyện gì xảy ra?

Trình biên dịch tự tạo cho bạn một constructor mặc định không nhận tham số và không làm gì ngoài lời gọi super() ngầm định. Nhưng ngay khi bạn tự viết bất kỳ constructor nào, constructor miễn phí đó biến mất. Vì vậy nếu bạn thêm một constructor có tham số mà vẫn muốn new Thing() hoạt động, bạn phải tự khai báo constructor không tham số.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu