Giới thiệu
Khi bắt đầu học Java, một trong những khái niệm đầu tiên bạn sẽ gặp là constructor. Đừng lo lắng nếu từ này có vẻ phức tạp — thực tế nó rất đơn giản.
1. Constructor là gì trong Java?
Constructor là một phương thức đặc biệt trong lớp với các đặc điểm sau:
- Có cùng tên với lớp.
- Không có kiểu trả về (thậm chí không phải là void).
- Chạy tự động khi bạn tạo một đối tượng với từ khóa
new.
👉 Tóm lại: Constructors giúp bạn khởi tạo (gán giá trị cho) các biến của đối tượng.
2. Tại sao cần Constructor?
Hãy tưởng tượng bạn đang tạo một bản thiết kế cho một chiếc xe ô tô. Mỗi chiếc xe cần có màu sắc và kiểu dáng. Nếu không có constructor, bạn sẽ phải thiết lập những giá trị này một cách thủ công mỗi lần. Nhưng với constructor, bạn có thể khởi tạo giá trị một cách nhanh chóng khi tạo đối tượng.
3. Các loại Constructor
- Constructor mặc định (Default Constructor)
- Constructor có tham số (Parameterized Constructor)
- Constructor nạp chồng (Overloaded Constructor)
- Constructor sao chép (Copy Constructor)
- Constructor không tham số (No-Argument Constructor)
4. Constructor mặc định (Default Constructor)
Nếu bạn không viết một constructor, Java sẽ tự động cung cấp cho bạn một cái (được gọi là constructor mặc định).
Ví dụ:
java
class Car {
String color;
String model;
}
public class Main {
public static void main(String[] args) {
Car c1 = new Car(); // constructor mặc định được gọi
System.out.println(c1.color); // null
System.out.println(c1.model); // null
}
}
👉 Ở đây, Java đã tạo ra một constructor trống ẩn cho chúng ta. Vì chúng ta không thiết lập giá trị nào, nên chúng ta nhận được giá trị mặc định (null cho Strings, 0 cho số).
Khi nào sử dụng? Sử dụng khi bạn không muốn thiết lập giá trị trong khi tạo đối tượng. Hữu ích nếu bạn dự định thiết lập giá trị sau này bằng cách sử dụng setters hoặc gán trực tiếp.
5. Constructor có tham số (Parameterized Constructor)
Bạn có thể tạo một constructor của riêng mình và truyền giá trị vào đó.
Ví dụ:
java
class Car {
String color;
String model;
// Constructor có tham số
Car(String c, String m) {
color = c;
model = m;
}
}
public class Main {
public static void main(String[] args) {
Car c1 = new Car("Đỏ", "BMW");
Car c2 = new Car("Xanh", "Tesla");
System.out.println(c1.color + " " + c1.model); // Đỏ BMW
System.out.println(c2.color + " " + c2.model); // Xanh Tesla
}
}
👉 Bây giờ, chúng ta có thể thiết lập giá trị trong khi tạo đối tượng. Không cần bước bổ sung nào.
Khi nào sử dụng? Mỗi khi đối tượng cần các giá trị khác nhau vào thời điểm tạo. Ví dụ: Khi thêm sản phẩm trong ứng dụng thương mại điện tử, mỗi sản phẩm có giá, tên và danh mục khác nhau.
6. Constructor nạp chồng (Overloaded Constructor)
Bạn có thể tạo nhiều constructor với các danh sách tham số khác nhau. Đây được gọi là nạp chồng constructor.
Ví dụ:
java
class Car {
String color;
String model;
// Constructor không tham số
Car() {
color = "Trắng";
model = "Không xác định";
}
// Constructor một tham số
Car(String c) {
color = c;
model = "Không xác định";
}
// Constructor hai tham số
Car(String c, String m) {
color = c;
model = m;
}
}
public class Main {
public static void main(String[] args) {
Car c1 = new Car();
Car c2 = new Car("Đen");
Car c3 = new Car("Xanh", "Honda");
System.out.println(c1.color + " " + c1.model); // Trắng Không xác định
System.out.println(c2.color + " " + c2.model); // Đen Không xác định
System.out.println(c3.color + " " + c3.model); // Xanh Honda
}
}
👉 Cùng một lớp, nhưng có nhiều cách khác nhau để khởi tạo các đối tượng.
Khi nào sử dụng? Khi bạn muốn có tính linh hoạt trong cách tạo đối tượng.
7. Constructor sao chép (Copy Constructor) trong Java
Không giống như C++, Java không có constructor sao chép tích hợp. Nhưng chúng ta có thể tạo constructor của riêng mình để sao chép giá trị từ một đối tượng này sang một đối tượng khác.
Ví dụ:
java
class Student {
String name;
int age;
// Constructor có tham số
Student(String n, int a) {
name = n;
age = a;
}
// Constructor sao chép
Student(Student s) {
name = s.name;
age = s.age;
}
}
public class Main {
public static void main(String[] args) {
Student s1 = new Student("Ajay", 21); // đối tượng gốc
Student s2 = new Student(s1); // đối tượng sao chép
System.out.println(s1.name + " - " + s1.age); // Ajay - 21
System.out.println(s2.name + " - " + s2.age); // Ajay - 21
}
}
✅ Tại sao sử dụng Constructor sao chép?
- Để sao chép đối tượng một cách dễ dàng.
- Để tạo ra một bản sao sâu (deep copy) (do đó thay đổi trong một đối tượng không ảnh hưởng đến đối tượng kia).
- Hữu ích khi làm việc với các đối tượng có nhiều thuộc tính.
8. Constructor không tham số (No-Argument Constructor)
(Constructor mặc định do người dùng định nghĩa)
Là gì? Một constructor mà bạn tự viết mà không có tham số. Nó cho phép bạn thiết lập giá trị mặc định tùy chỉnh thay vì giá trị mặc định tích hợp của Java.
Khi nào sử dụng? Khi bạn muốn tất cả các đối tượng mới đều có giá trị mặc định ban đầu. Ví dụ: Một người chơi game mới có thể luôn bắt đầu với 100 sức khỏe và 0 điểm số.
Kết luận
👉 Về mặt kỹ thuật, Java chỉ có 2 loại chính:
- Constructor mặc định
- Constructor có tham số
Các loại còn lại là các biến thể do lập trình viên tạo ra.
Các phương pháp tốt nhất
- Sử dụng constructor để đảm bảo tính nhất quán trong việc khởi tạo đối tượng.
- Tránh việc tạo nhiều constructor không cần thiết có thể làm phức tạp mã nguồn.
Những cạm bẫy phổ biến
- Quên không gọi constructor cha trong constructor con có tham số.
- Sử dụng constructor không tham số khi có tham số là cần thiết, dẫn đến việc khởi tạo không đúng.
Mẹo hiệu suất
- Sử dụng constructor sao chép để giảm thiểu việc tạo đối tượng không cần thiết.
- Đặt các giá trị mặc định hợp lý trong constructor để tránh lỗi thời gian chạy.
Xử lý sự cố
- Nếu bạn gặp lỗi
NullPointerException, hãy kiểm tra xem bạn đã khởi tạo tất cả các biến trong constructor hay chưa. - Nếu đối tượng không khởi tạo đúng cách, hãy đảm bảo rằng bạn đã gọi đúng constructor.
Câu hỏi thường gặp
1. Constructor có thể trả về giá trị không?
Không, constructor không có kiểu trả về.
2. Một lớp có thể có bao nhiêu constructor?
Một lớp có thể có nhiều constructor miễn là chúng có danh sách tham số khác nhau.
3. Tại sao nên sử dụng constructor sao chép?
Để dễ dàng sao chép các đối tượng mà không cần tạo lại từng thuộc tính.