Học viên: Phạm Thế Dương
Email: duongphamhn97@gmail.com
Bài viết gốc: https://www.javatpoint.com/static-keyword-in-java

Từ khoá static trong Java được sử dụng chủ yếu trong việc quản lý dữ liệu. Ta có thể áp dụng từ khoá static với biến, phương thức, block và các nested class (class lồng trong class khác). Từ khoá static thuộc về class chứ không thuộc về đối tượng của class đó.

Static có thể áp dụng cho:

  1. Biến (khi đó còn gọi là biến của class)
  2. Phương thức (khi đó còn gọi là phương thức của class)
  3. Block
  4. Nested class

1) Biến static trong java

  • Biến static có thể được dùng để tham chiếu tới thuộc tính chung của tất cả các đối tượng, chẳng hạn như tên công ty của các nhân viên, tên trường đại học của các sinh viên, v.v.
  • Biến static chỉ chiếm bộ nhớ một lần trong vùng nhớ của class tại thời điểm class được nạp vào bộ nhớ.

Ưu điểm của biến static
Khiến chương trình hiệu quả hơn về mặt bộ nhớ (tiết kiệm bộ nhớ).
Ta sẽ hiểu vấn đề này hơn với ví dụ sau, giả sử nếu không có biến static

class Student {
    int rollno;
    String name;
    String college = "ITS";
}

Nếu như có 500 sinh viên trong trường đại học, giờ thì tất cả các thành viên dữ liệu đối tượng sẽ chiếm bộ nhớ mỗi lần khi đối tượng được khởi tạo. Tất cả sinh viên có mã số và tên riêng biệt, vì vậy thành viên dữ liệu đối tượng dùng trong trường hợp này là hợp lý. Tuy nhiên ở đây, “college” thể hiện thuộc tính chung của tất cả các đối tượng. Nếu ta cho nó thành biến static, thuộc tính này chỉ chiếm bộ nhớ một lần.

Thuộc tính static trong Java được chia sẻ cho tất cả các đối tượng.

Ví dụ về biến static

// Chương trình Java minh hoạ việc sử dụng biến static 
class Student {
    int rollno; // biến đối tượng
    String name;
    static String college = "ITS"; // biến static

    // Constructor
    Student(int r, String n) {
        rollno = r;
        name = n;
    }

    // Phương thức dùng để in ra giá trị
    void display() {
        System.out.println(rollno + " " + name + " " + college);
    }
}

// Test class để in ra giá trị các đối tượng
public class TestStaticVariable1 {
    public static void main(String[] args) throws Exception {
        Student s1 = new Student(111, "Karan");
        Student s2 = new Student(222, "Aryan");
        s1.display();
        s2.display();
        // Ta có thể thay đổi giá trị college của tất cả các đối tượng bằng một dòng
        // code
        Student.college = "BBDIT";
        System.out.println("Gia tri cac doi tuong sau khi thay doi bien static");
        s1.display();
        s2.display();
    }
}

Kết quả:

111 Karan ITS
222 Aryan ITS
Gia tri cac doi tuong sau khi thay doi bien static
111 Karan BBDIT
222 Aryan BBDIT

static java memory

Chương trình đếm không sử dụng biến static

Ở ví dụ này, ta sẽ tạo một biến đối tượng count tăng dần trong constructor. Vì biến đối tượng chiếm bộ nhớ khi đối tượng được khởi tạo, mỗi đối tượng sẽ có một giá trị riêng của biến này. Nếu giá trị của count ở đối tượng này được tăng lên, nó không ảnh hưởng đến giá trị của count ở đối tượng khác. Vì thế mỗi đối tượng sẽ có giá trị của count là 1.

// Chương trình Java minh hoạ việc sử dụng biến đối tượng
// chiếm bộ nhớ mỗi lần đối tượng được khởi tạo
class Counter {
    int count = 0; // sẽ chiếm bộ nhớ mỗi khi đối tượng được khởi tạo

    Counter() {
        count++;
        System.out.println(count);
    }

    public static void main(String args[]) {
        Counter c1 = new Counter();
        Counter c2 = new Counter();
        Counter c3 = new Counter();
    }
}

Kết quả:

1
1
1

Chương trình đếm sử dụng biến static

Như chúng ta đã nhắc đến ở trên, biến static chỉ chiếm bộ nhớ một lần, nếu có bất kỳ đối tượng nào thay đổi giá trị của biến static, nó sẽ lưu lại thay đổi này.

// Chương trình Java minh hoạ biến static
// được chia sẻ chung với tất cả các đối tượng
class Counter2 {
    static int count = 0; // chỉ chiếm bộ nhớ một lần và lưu lại các thay đổi của giá trị

    Counter2() {
        count++;
        System.out.println(count);
    }

    public static void main(String args[]) {
        Counter2 c1 = new Counter2();
        Counter2 c2 = new Counter2();
        Counter2 c3 = new Counter2();
    }
}

Kết quả:

1
2
3

2) Phương thức static trong Java

  • Phương thức static thuộc về class chứ không thuộc về đối tượng của class đó
  • Phương thức static có thể được gọi mà không cần khởi tạo đối tượng của class
  • Phương thức static có thể truy cập thành viên dữ liệu static và thay đổi giá trị của nó

Ví dụ phương thức static

// Chương trình Java minh hoạ việc sử dụng phương thức static
class Student {
    int rollno;
    String name;
    static String college = "ITS";

    // Phương thức static để thay đổi giá trị biến static
    static void change() {
        college = "BBDIT";
    }

    Student(int r, String n) {
        rollno = r;
        name = n;
    }

    void display() {
        System.out.println(rollno + " " + name + " " + college);
    }
}

// Test class để khởi tạo và in giá trị các đối tượng
public class TestStaticMethod {
    public static void main(String args[]) {
        Student.change(); // gọi phương thức thay đổi giá trị biến static
        Student s1 = new Student(111, "Karan");
        Student s2 = new Student(222, "Aryan");
        Student s3 = new Student(333, "Sonoo");
        s1.display();
        s2.display();
        s3.display();
    }
}

Kết quả:

111 Karan BBDIT
222 Aryan BBDIT
333 Sonoo BBDIT

Một ví dụ khác về phương thức static thực hiện tính toán

// Chương trình Java tính lập phương của một số cho trước sử dụng biến static
class Calculate {
    static int cube(int x) {
        return x * x * x;
    }

    public static void main(String args[]) {
        int result = Calculate.cube(5);
        System.out.println(result);
    }
}

Kết quả:

125

Hạn chế của phương thức static
Có hai hạn chế chính của phương thức static. Đó là:

  1. Phương thức static không thể sử dụng thành viên dữ liệu non-static hoặc gọi phương thức non-static một cách trực tiếp.
  2. thissuper không thể sử dụng trong ngữ cảnh static.
class A {
    int a = 40; // non-static

    public static void main(String args[]) {
        System.out.println(a);
    }
}  

Kết quả:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
        Cannot make a static reference to the non-static field a

        at A.main(A.java:5)

Q) Tại sao phương thức main trong Java là static?

Trả lời: Vì không cần khởi tạo đối tượng để gọi phương thức static. Nếu main là phương thức non-static, JVM cần phải khởi tạo đối tượng trước rồi mới gọi phương thức main, điều này dẫn tới việc tốn thêm bộ nhớ.

3) Static block trong Java

  • Được sử dụng để khởi tạo thành viên dữ liệu static
  • Được thực thi trước phương thức main tại thời điểm nạp class vào bộ nhớ.

Ví dụ static block

class A2 {
    static {
        System.out.println("static block is invoked");
    }

    public static void main(String args[]) {
        System.out.println("Hello main");
    }
}

Kết quả:

static block is invoked
Hello main

Q) Ta có thể thực thi chương trình mà không cần phương thức main không?

Trả lời: Không thể, có một cách là sử dụng static block tuy nhiên cách này chỉ hoạt động với JDK 1.6 trở xuống. Kể từ JDK 1.7, không thể thực thi chương trình Java mà không có phương thức main.

class A3 {
    static {
        System.out.println("static block is invoked");
        System.exit(0);
    }
}

Kết quả với JDK 1.6 trở xuống:

static block is invoked

Kết quả với JDK 1.7 trở lên:

Error: Main method not found in class A3, please define the main method as:
   public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application