Trong ngôn ngữ lập trình Java (gọi tắt là Java), một thành viên (biến, phương thức, khối khởi tạo, lớp lồng) của lớp đi kèm với từ khóa static được dùng để xác định thành viên này thuộc về lớp chứ không thuộc về thể hiện của lớp. Nghĩa là toàn bộ đối tượng của lớp sẽ dùng chung thành viên static này. Chúng ta cùng lần lượt tìm hiểu chi tiết từng thành viên static.
Biến static (static variable)
Nếu một biến đi kèm với từ khóa static thì biến này sẽ thuộc về lớp, nghĩa là chỉ được khởi tạo duy nhất 1 lần để dùng chung cho toàn bộ đối tượng được tạo ra, không phân biệt đối tượng được tạo trước hay được tạo sau. Xem xét một ví dụ sử dụng biến static đơn giản sau:
class A{
static int number = 0;
A(){
number++;
}
}
public class Main{
public static void main(String[] args){
A a1 = new A();
System.out.println("Value of number is: " + a1.number);
A a2 = new A();
System.out.println("Value of number is: " + a2.number);
System.out.println("Value of number is: " + ++A.number);
}
}
Kết quả in ra là:
Value of number is: 1
Value of number is: 2
Value of number is: 3
Vì sau khi đối tượng a1 được tạo ra thì biến number đã mang giá trị 1, nên khi đối tượng a2 được tạo ra thì biến number sẽ mang giá trị 2. Vì biến static thuộc về lớp A nên ngoài việc truy cập biến static thông qua các đối tượng thì chúng ta cũng có thể truy cập biến static thông qua bản thân lớp như minh họa ở phương thức println cuối cùng.
Nếu loại bỏ từ khóa static của biến number thì kết quả in ra là (lưu ý loại bỏ phương thức println cuối cùng vì không thể truy cập 1 biến thông thường thông qua lớp):
Value of number is: 1
Value of number is: 1
Mục đích của biến static là để chia sẻ, vì thế cần phải lưu ý một số điểm sau khi thao tác với các biến static:
Biến static không thể bị ghi đè (overriding) khi kế thừa vì nếu bị ghi đè thì chúng không còn được chia sẻ giữa các đối tượng cùng lớp với nhau nữa.
Trong các giao diện (interface) thì tất cả các biến đều phải khai báo với từ khóa static để các lớp triển khai giao diện không thể ghi đè được các biến này.
Khối khởi tạo static (static block)
Khối khởi tạo static là một mở rộng cho biến static nhằm dùng để khởi tạo giá trị cho các biến static. Tương tự như biến static, khối khởi tạo static cũng thuộc về lớp. Nếu có nhiều khối khởi tạo static trong một lớp thì các khối static này sẽ được thực thi tuần tự theo thứ tự khai báo. Vì chỉ là một khối khởi tạo nên khối khởi tạo static sẽ không thể được truy cập từ bất kỳ đối tượng hay lớp nào, đây cũng là lý do mà khối khởi tạo static sẽ không có tên để truy cập. Chúng ta cùng mở rộng ví dụ trước đó bằng cách bổ sung thêm khối khởi tạo static.
class A{
static int number = 0;
A(){
number++;
}
static{
number = 99;
}
static{
number = 10;
}
}
public class Main{
public static void main(String[] args) {
A a1 = new A();
System.out.println("Value of number is: " + a1.number);
A a2 = new A();
System.out.println("Value of number is: " + a2.number);
System.out.println("Value of number is: " + ++A.number);
}
}
Kết quả in ra là:
Value of number is: 11
Value of number is: 12
Value of number is: 13
Mặc dù biến number được gán giá trị khá nhiều lần trong các khối static, nhưng vì được thực thi tuần tự nên cuối cùng là biến number sẽ mang giá trị khởi tạo là 10. Khi đối tượng a1 và a2 được lần lượt tạo ra thì giá trị của biến number sẽ là 11 và 12 tương ứng.
Tất nhiên trong ví dụ này chúng ta có thể không cần sử dụng khối khởi tạo static và có thể khởi tạo giá trị cho biến static ngay lúc khai báo, nhưng đối với một số ứng dụng chẳng hạn sử dụng danh sách liên kết thì chúng ta không thể cùng lúc vừa khai báo danh sách liên kết vừa khởi tạo giá trị cho các node trong danh sách được, vì thế chúng ta cần khối tạo static để khởi tạo các node ban đầu của danh sách liên kết.
Phương thức static (static method)
Cũng giống như biến static và khối khởi tạo static, phương thức static cũng thuộc về lớp và có thể truy cập thông qua cả đối tượng và lớp như biến static (vì phương thức có tên ^_^). Cùng xem xét cách sử dụng phương thức static thông qua ví dụ sau:
class A{
static int number = 0;
A(){
number++;
}
static{
number = 10;
}
static{
number = 20;
}
static void setNumber(int newNumber){
number = newNumber;
}
}
public class Main{
public static void main(String[] args) {
A a1 = new A();
System.out.println("Value of number is: " + a1.number);
A a2 = new A();
System.out.println("Value of number is: " + a2.number);
System.out.println("Value of number is: " + ++A.number);
A.setNumber(5);
System.out.println("Value of number is: " + a1.number);
A a3 = new A();
System.out.println("Value of number is: " + a3.number);
}
}
Kết quả in ra là:
Value of number is: 21
Value of number is: 22
Value of number is: 23
Value of number is: 5
Value of number is: 6
Mục đích của phương thức static là để thao tác trên các biến static, vì thế cần phải lưu ý một số điểm sau khi thao tác với các phương thức static:
Phương thức static khổng thể bị ghi đè (overriding) khi kế thừa vì nếu bị ghi đè thì chúng không còn được chia sẻ giữa các đối tượng cùng lớp với nhau nữa.
Phương thức static không thể truy cập các biến thông thường và các hàm thông thường khác vì các biến thông thường và các hàm thông thường khác có thể bị ghi đè.
Trong các giao diện (interface) thì tất cả các phương thức KHÔNG được khai báo với từ khóa static để đảm bảo các lớp triển khai giao diện có thể ghi đè được các phương thức này.
Lớp lồng static (static nested class)
Sự khác biệt duy nhất giữa một lớp lồng bình thường (inner class) và một lớp lồng static (static nested class) là lớp lồng static chỉ có thể truy cập tới các thành viên static của lớp ngoài (outer class).
Lưu ý là từ khóa static chỉ được áp dụng cho lớp lồng chứ không được áp dụng cho lớp bình thường, vì thế mà ngay ở đầu bài viết chỉ đề cập đến thành viên của lớp.