1. Tạo đối tượng
Cuối cùng cũng đến phần tạo đối tượng rồi. Bạn đã từng gặp cái này trước đây, chỉ là giờ mình sẽ phân tích kỹ hơn thôi. Thực ra tạo đối tượng dễ lắm.
Để tạo đối tượng, bạn dùng toán tử new. Thường thì bạn tạo một instance (đối tượng) mới của class và lưu nó vào biến cùng kiểu.
Lop ten = new Lop(thamSo);
Ở đây Lop — kiểu của đối tượng, ten — tên biến (thường viết thường, ví dụ cat), còn bên phải = — là tạo đối tượng mới của class đó.
Ví dụ:
| Mã | Ghi chú |
|---|---|
|
Tạo đối tượng kiểu object |
|
Tạo đối tượng kiểu Cat |
|
Tạo đối tượng StreamReader với tham số |
Rất nhiều dev đặt tên biến giống tên class, chỉ khác là viết thường. Người mới học nhìn code kiểu này dễ bị rối:
| Mã |
|---|
|
|
|
Thực ra code này không có gì ghê gớm đâu — đây là code bình thường, tạo biến và khởi tạo nó bằng đối tượng cùng kiểu.
Bên trái — khai báo biến, bên phải — tạo đối tượng mới trong bộ nhớ bằng new. Xong!
2. Constructor
Chắc bạn cũng hay thấy khi tạo đối tượng thì truyền vào một số tham số. Có đối tượng thì truyền tham số, có cái thì không. Vậy cơ chế truyền tham số này hoạt động thế nào?
Cũng đơn giản thôi: mỗi class có một (hoặc nhiều) phương thức đặc biệt xử lý tham số khi tạo đối tượng. Mấy phương thức này gọi là constructor. Một phương thức thì gọi là constructor.
Nhận biết constructor với phương thức thường cũng dễ. Constructor có hai đặc điểm:
- tên constructor giống tên class (và viết hoa chữ cái đầu)
- constructor không có kiểu trả về (ngay cả void cũng không viết).
Nhìn chung nó sẽ như này:
modifier Lop(thamSo)
{
code constructor
}
Ví dụ khai báo constructor:
public class Point
{
public int X;
public int Y;
public Point(int x, int y) // Constructor
{
X = x;
Y = y;
}
}
Cách dùng:
Point p = new Point(5, 10); // Gọi constructor
Khi tạo đối tượng bằng new Point(5, 10) sẽ gọi constructor với hai tham số, dùng để khởi tạo trường X và Y.
Đôi khi tham số của constructor trùng tên với trường — cho tiện. Trường hợp này giải quyết bằng từ khóa this:
public Point(int x, int y)
{
this.x = x; // this.x — trường của đối tượng, x — tham số constructor
this.y = y;
}
3. Gọi constructor
Khi bạn viết new Lop(thamSo), thì C#:
- tạo đối tượng mới trong bộ nhớ,
- gọi constructor phù hợp, truyền tham số vào.
Ví dụ với class mèo:
public class Cat
{
public string Name;
public int Age;
public Cat(string name, int age)
{
Name = name;
Age = age;
}
}
Cách dùng:
Cat cat = new Cat("Vaska", 2); // Được: gọi constructor với hai tham số
Cat cat2 = new Cat("Vaska"); // Không được: không có constructor này — lỗi biên dịch
Cat cat3 = new Cat(); // Không được: không có constructor không tham số — lỗi biên dịch
Nếu class chỉ có constructor có tham số, bạn bắt buộc phải truyền giá trị cho nó khi tạo đối tượng.
4. Nhiều constructor
Nhưng nếu muốn, bạn có thể thêm nhiều constructor vào class. Không giới hạn số lượng constructor hay tham số. Khi tạo đối tượng, compiler sẽ tự chọn constructor phù hợp với tham số bạn truyền.
Ví dụ:
public class Cat
{
public const int KHONG_BIET = -1;
public string Name;
public int Age;
public Cat(string name, int age)
{
Name = name;
Age = age;
}
public Cat(string name)
{
Name = name;
Age = KHONG_BIET; // Giá trị "mặc định" cho tuổi không biết
}
}
Cách dùng:
Cat cat1 = new Cat("Vaska", 2); // Dùng constructor đầu tiên
Cat cat2 = new Cat("Murka"); // Dùng constructor thứ hai
Cat cat3 = new Cat(); // Lỗi! Không có constructor không tham số
Giả sử tuổi mèo có thể không biết. Trường hợp này mình thêm hằng số đặc biệt — KHONG_BIET và constructor chỉ nhận tên mèo.
Lưu ý là mình vẫn khởi tạo cả hai biến class trong cả hai constructor. Tham số không biết/thừa thì thay bằng hằng số KHONG_BIET.
5. Constructor mặc định
Nếu class của bạn không có constructor nào, compiler sẽ tự động thêm constructor rỗng không tham số:
public ClassName()
{
}
Nhưng nếu class đã có ít nhất một constructor tự khai báo — thì constructor rỗng sẽ không được thêm tự động.
Ví dụ 1:
public class Cat
{
public string Name;
public int Age;
}
// Được:
Cat cat = new Cat(); // Sẽ gọi constructor mặc định (không tham số)
Ví dụ 2:
public class Cat
{
public string Name;
public int Age;
public Cat(string name) { Name = name; }
}
// Không được:
Cat cat = new Cat(); // Lỗi: không còn constructor không tham số!
6. Khởi tạo biến
Trong C#, biến class có thể khởi tạo ngay khi khai báo, hoặc trong constructor.
Ví dụ:
public class Cat
{
public string Name;
public int Age = -1; // Giá trị khởi đầu
public Cat(string name, int age)
{
Name = name;
Age = age; // Ghi đè giá trị khởi đầu
}
public Cat()
{
Name = "KhongTen";
// Age vẫn là -1 (giá trị khởi đầu)
}
}
Giải thích:
- Khi tạo bằng new Cat("Vaska", 2) biến Age ban đầu là -1, nhưng constructor sẽ gán lại thành 2.
- Khi tạo bằng new Cat() — Age vẫn là -1.
7. Thứ tự khởi tạo biến
Dữ liệu của đối tượng mới sẽ được khởi tạo theo thứ tự:
- Trường của class đầu tiên nhận giá trị mặc định (0 cho int, null cho kiểu tham chiếu, v.v.).
- Sau đó chạy các initializer bạn khai báo khi định nghĩa trường, theo thứ tự xuất hiện trong code.
- Và cuối cùng mới chạy code trong constructor.
Biến được khởi tạo trước constructor và theo thứ tự khai báo. Nên chú ý nếu các trường phụ thuộc lẫn nhau.
Ví dụ sai
Trường không static không thể khởi tạo bằng biến không static khác:
public class Solution
{
public int a = 1;
public int b = a; // không dùng được a
public int c = a + b; // không dùng được a và b
}
// Code này sẽ báo lỗi biên dịch!
Ví dụ đúng
Với biến static mọi thứ sẽ chạy ngon:
public class Solution
{
public static int a = 1; // Gán rõ ràng a = 1
public static int b = a + 2; // b = 1 + 2 ⇒ 3
public static int c = a + b + 3; // c = 1 + 3 + 3 ⇒ 7
public Solution()
{
Console.WriteLine($"a = {a}, b = {b}, c = {c}");
// Sẽ in: a = 1, b = 3, c = 7 — đúng như mong đợi
}
}
Ví dụ đúng 2
Với trường static bạn còn có thể viết như này:
public class Solution
{
public static int a = b + c + 1; // b và c vẫn là 0
public static int b = a + c + 2; // a == 1, c vẫn là 0
public static int c = a + b + 3; // a == 1, b == 3
}
GO TO FULL VERSION