[Java] Từ khóa static trong Java

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 😉

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 thissuper 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 😉

 

 

 

 

 

Advertisement