Từ khóa static trong Java được dùng trong việc quản lý bộ nhớ.
Từ khóa static thuộc về class chứ không thuộc về objects ( instance of the class )
Chúng ta có thể áp dụng từ khóa static với variables, methods, blocks and nested class
Q: Tại sao cần sử dụng từ khóa static?
A: Như đã biết khi chúng ta tạo một class và muốn sử dụng một biến hoặc phương thức được khai báo trong class là điều không thể. Vì Java là một OOP language có nghĩa là chúng ta cần phải có một đối tượng để truy cập vào biến và phương thức trong và ngoài class và khi ta đã khởi tạo object thì biến và phương thức là của riêng object đó chứ không phải của class. Vậy khi đó đặt ra câu hỏi là khi cần một biến hoặc phương thức mà chúng chỉ thuộc về class, được dùng chung cho tất cả các đối tượng được tạo ra và tiết kiệm bộ nhớ thì phải làm thế nào? Câu trả lời là dùng từ khóa static 😉
Tóm Tắt
1. Java static variable
Trong Java, biến có thể được khai báo cùng với từ khóa static, và lúc đó nó có thể được gọi là class variable
Việc cấp phát bộ nhớ cho biến static chỉ xảy ra một lần khi class được nạp vào bộ nhớ
Giá trị mặc định khi khai báo và khởi tạo biến static và non-static là giống nhau, cụ thể:
- primitive integers (long, int, short, byte): 0
- primitive floating points (double, float): 0.0
- boolean: false
- object references: null
Biến static có thể được sử dụng làm thuộc tính chung, để dùng chung dữ liệu cho all the objects ( or instances ) của lớp đó và điều đó giúp cho chương trình tiết kiệm bộ nhớ hơn
Ex1:
Khi không dùng biến static
public class Student { int id; String name; String college = "PTIT"; }
Giả sử có 1000 sinh viên trong trường, mỗi khi tạo ra một đối tượng thì tất cả dữ liệu của đối tượng sẽ được cấp phát bộ nhớ. Mỗi sinh viên sẽ có id và tên riêng nên 2 trường này sẽ khai báo là biến thông thường. Nhưng vì tất cả sinh viên đều cùng một trường nên college là một thuộc tính chung cho tất cả các đối tượng, nên để chương trình cải thiện về mặt bộ nhớ thì college nên được khai báo là static và nó sẽ chỉ lấy bộ nhớ một lần.
package edu.java.basic.modifiers; public class Student { int id; String name; static String college = "PTIT"; public Student(int id, String name) { this.id = id; this.name = name; } public void display() { System.out.println(id + " - " + name + " - " + college); } public static void main(String[] args) { Student s1 = new Student(101, "Tùng"); s1.display(); Student s2 = new Student(102, "Huỳnh"); s2.display(); } }
Output:
101 - Tùng - PTIT 102 - Huỳnh - PTIT
Ex2:
Chúng ta tạo ra một class Counter có một biến đếm là count được tăng lên trong constructor
TH1: Không đặt là static
Mỗi một đối tượng được tạo ra sẽ có một bản sao khác nhau của biến count, vì thế các đối tượng sẽ luôn có biến count bằng 1
package edu.java.basic.modifiers; public class Counter { int count = 0; public Counter() { count++; System.out.println("count = " + count); } public static void main(String[] args) { Counter c1 = new Counter(); Counter c2 = new Counter(); Counter c3 = new Counter(); } }
Output:
count = 1 count = 1 count = 1
TH2: Đặt là static
Như đã nói ở trên, biến static sẽ chỉ cấp phát bộ nhớ một lần. Vì vậy, nếu có đối tượng làm thay đổi giá trị của biến tĩnh thì giá trị của nó sẽ được giữ lại
package edu.java.basic.modifiers; public class Counter { static int count = 0; public Counter() { count++; System.out.println("count = " + count); } public static void main(String[] args) { Counter c1 = new Counter(); Counter c2 = new Counter(); Counter c3 = new Counter(); } }
Output:
count = 1 count = 2 count = 3
Static final variables
static final variables được gọi là hằng số 🙂
public class MyClass { public static final int MY_VAR = 22; }
Chú ý: Một hằng số nên được viết hoa và nếu có nhiều từ như ví dụ trên thì phân cách bằng dấu gạch dưới (_)
Luôn phải khởi tạo giá trị, nếu không khởi tạo giá trị nó sẽ ném ra một lỗi biên dịch
Biến được khai báo là static final tức là: khi giá trị của biến không thay đổi, luôn luôn có giá trị duy nhất (số PI,…) thì đặt là final, và ta muốn sử dụng nó dễ dàng, tiết kiệm bộ nhớ thì khai báo là static 😉
Ngoài ra, chúng ta cần lưu ý một điểm quan trọng là trong các thuộc tính trong interface mặc định có 3 đặc điểm là public static final
public static final int AGE = 22;
Nếu chỉ khai báo thuộc tính trong interface là
int AGE = 22;
thì vẫn không sai, và Java sẽ ngầm hiểu đó là public static final int AGE = 22
2. Java static method
Nếu khai báo một phương thức với từ khóa static thì phương thức đó được gọi là phương thức static (static method)
Đó chính là stateless design trong thiết kế, tức là giả sử có class A gọi đến một phương thức add() trong class B, gọi xong phương thức đó rồi thôi, giữa 2 bên không có ràng buộc thì ta viết hàm add đó là static và hàm đó có thể dùng chung, thằng nào gọi đến cũng được và không cần khởi tạo object 🙂 Nhưng nếu như khi A gọi hàm add() mà hàm đó còn keep lại dữ liệu của A thì hàm đó không được đặt static, và phải khởi tạo object của B để truy cập đến
Một số đặc điểm:
A static method thuộc về class chứ không thuộc về object ( instance )
A static method có thể được truy cập trực tiếp bởi tên lớp mà không cần tạo bất kỳ một object nào
A static method chỉ có thể truy cập dữ liệu static và thay đổi giá trị của nó, nó không thể truy cập dữ liệu non-static
A static method chỉ có thể gọi một static method khác, nó không thể gọi được một non-static method
Từ khóa this và super không thể được sử dụng trong ngữ cảnh static
Ex1:
Ví dụ về phương thức static truy cập dữ liệu static và thay đổi giá trị của nó
package edu.java.basic.modifiers; public class Student { int id; String name; static String college = "PTIT"; public Student(int id, String name) { this.id = id; this.name = name; } public void display() { System.out.println(id + " - " + name + " - " + college); } public static void change() { college = "Học viện CNBCVT"; } public static void main(String[] args) { Student s1 = new Student(101, "Tùng"); Student s2 = new Student(102, "Huỳnh"); System.out.println("******* Before *******"); s1.display(); s2.display(); Student.change(); //Change the common property of all objects (static field) System.out.println("******* After *******"); s1.display(); s2.display(); } }
Output:
******* Before ******* 101 - Tùng - PTIT 102 - Huỳnh - PTIT ******* After ******* 101 - Tùng - Học viện CNBCVT 102 - Huỳnh - Học viện CNBCVT
Q: Tại sao phương thức main trong Java là static?
A: Đọc thêm tại đây hoặc đây 😉
3. Java static block
Khối static được dùng để khởi tạo hoặc thay đổi giá trị của các static data
Nó được thực thi trước phương thức main tại thời gian tải lớp
Một class có thể có nhiều static blocks
Ex1:
Khối static được thực thi trước phương thức main
package edu.java.basic.modifiers; public class MyClass { static { System.out.println("-----> Khối static đã được gọi đến trước phương thức main!"); } public static void main(String args[]) { System.out.println("-----> Main được gọi tới!"); } }
Output:
-----> Khối static đã được gọi đến trước phương thức main! -----> Main được gọi tới!
Ex2:
Nhiều static blocks trong một class
package edu.java.basic.modifiers; public class MyClass { static int age; static String name; static { System.out.println("Khối static 1 được gọi"); age = 18; name = "Hương"; } static { System.out.println("Khối static 2 được gọi"); age = 20; name = "Thảo"; } public static void main(String args[]) { //Giá trị được thay đổi theo khối thứ 2 System.out.println("Age = " + age); System.out.println("Name = " + name); } }
Output:
Khối static 1 được gọi Khối static 2 được gọi Age = 20 Name = Thảo
4. Java static class
Một class được có thể được đặt là static chỉ khi nó là một nested class (tức nằm trong một lớp khác)
The nested static class có thể được truy cập mà không cần một object của outer class (lớp bên ngoài)
Ex1:
package edu.java.basic.modifiers; public class MyClass { static class MyNestedClass { static String country = "Việt Nam"; } public static void main(String args[]) { System.out.println(MyNestedClass.country); } }
Output:
Việt Nam
Bài viết bên trên mình tổng hợp lại chỉ là các lý thuyết cơ bản, trong thực tế làm việc sẽ có nhiều trường hợp áp dụng khác nhau. Bài viết nếu có chỗ nào chưa chính xác các bạn comment góp ý để mình sửa lại 😉