Rate this post

Trong hướng dẫn này, chúng ta sẽ khám phá chi tiết từ khóa static của ngôn ngữ Java.

Chúng ta sẽ tìm hiểu làm thế nào chúng ta có thể áp dụng từ khóa static cho các biến, phương thức, khối và các class lồng nhau cũng như sự khác biệt của nó.

Cấu trúc của từ khóa static

Trong ngôn ngữ lập trình Java, từ khóa static có nghĩa là thành viên cụ thể thuộc về một loại, chứ không phải là một thể hiện của loại đó.

Điều này có nghĩa là chúng ta sẽ chỉ tạo một phiên bản của thành viên static đó được chia sẻ trên tất cả các phiên bản của class.

Chúng ta có thể áp dụng từ khóa cho các biến, phương thức, khối và các class lồng nhau.

Các trường static (Hoặc các biến class)

Trong Java, khi chúng ta khai báo một trường static, chính xác một bản sao của trường đó được tạo và chia sẻ giữa tất cả các phiên bản của class đó.

Chúng ta khởi tạo một class bao nhiêu lần không quan trọng. Sẽ luôn chỉ có một bản sao của trường static thuộc về nó. Giá trị của trường static này được chia sẻ trên tất cả các đối tượng của cùng một class.

Từ góc độ bộ nhớ, các biến static được lưu trữ trong bộ nhớ heap.

Ví dụ về Trường static

Giả sử chúng ta có một class Car với một số thuộc static (biến thể hiện).

Bất cứ khi nào chúng ta khởi tạo các đối tượng mới từ class Car này, mỗi đối tượng mới sẽ có bản sao riêng biệt của các biến đối tượng này.

Tuy nhiên, giả sử chúng ta muốn một biến chứa số lượng đối tượng Xe được khởi tạo và được chia sẻ trên tất cả các phiên bản để chúng có thể truy cập và tăng nó khi khởi tạo.

Đó là nơi các biến static xuất hiện:

public class Car {
    private String name;
    private String engine;
    
    public static int numberOfCars;
    
    public Car(String name, String engine) {
        this.name = name;
        this.engine = engine;
        numberOfCars++;
    }

    // getters and setters
}

Bây giờ đối với mọi đối tượng của class này mà chúng ta khởi tạo, cùng một bản sao của biến numberOfCars được tăng lên.

Vì vậy, đối với trường hợp này, những điều này sẽ đúng, ta kiểm thử sử dụng test

@Test
public void whenNumberOfCarObjectsInitialized_thenStaticCounterIncreases() {
    new Car("Jaguar", "V8");
    new Car("Bugatti", "W16");
 
    assertEquals(2, Car.numberOfCars);
}

Lý do để sử dụng trường static

Dưới đây là một số lý do khi chúng tôi muốn sử dụng các trường static:

  • khi giá trị của biến độc lập với các đối tượng
  • khi giá trị được cho là được chia sẻ trên tất cả các đối tượng

Những điểm chính cần nhớ

Vì các biến static thuộc về một class nên chúng ta có thể truy cập chúng trực tiếp bằng tên class. Vì vậy, chúng tôi không cần bất kỳ tham chiếu đối tượng nào.

Chúng ta chỉ có thể khai báo các biến static ở cấp class.

Chúng ta có thể truy cập các trường static mà không cần khởi tạo đối tượng.

Cuối cùng, chúng ta có thể truy cập các trường static bằng tham chiếu đối tượng (chẳng hạn như ford.numberOfCars++). Nhưng chúng ta nên tránh điều này bởi vì sẽ rất khó để xác định xem đó là instance variable hay class variable. Thay vào đó, chúng ta phải luôn tham chiếu đến các biến static bằng cách sử dụng tên class (Car.numberOfCars++).

Các phương thức static (Hoặc Phương thức class)

Tương tự như các trường static, các phương thức static cũng thuộc về một class thay vì một đối tượng. Vì vậy, chúng ta có thể gọi chúng mà không cần tạo đối tượng của class mà chúng cư trú.

Ví dụ về Phương thức static

Chúng tôi thường sử dụng các phương thức static để thực hiện một thao tác không phụ thuộc vào việc tạo phiên bản.

Để chia sẻ mã trên tất cả các phiên bản của class đó, chúng tôi viết nó theo một phương thức static:

static void setNumberOfCars(int numberOfCars) {
    Car.numberOfCars = numberOfCars;
}

Chúng tôi cũng thường sử dụng các phương thức static để tạo các class tiện ích hoặc trình trợ giúp để chúng tôi có thể lấy chúng mà không cần tạo một đối tượng mới của các class này.

Ví dụ, chúng ta có thể xem các class tiện ích Collections hoặc Math từ JDK, StringUtils từ Apache hoặc CollectionUtils từ Spring framework và nhận thấy rằng tất cả các phương thức tiện ích của chúng là static.

Lý do sử dụng phương pháp static

Hãy xem xét một vài lý do tại sao chúng ta muốn sử dụng các phương thức static:

  • Để truy cập/thao tác với các biến static và các phương thức static khác không phụ thuộc vào các đối tượng.
  • Các phương thức static được sử dụng rộng rãi trong các class tiện ích và trợ giúp.

Những điểm chính cần nhớ

Các phương thức static trong Java được giải quyết tại thời điểm biên dịch. Vì ghi đè phương thức là một phần của Đa hình thời gian chạy, nên không thể ghi đè các phương thức static.

  • Các phương thức trừu tượng không thể static.
  • các phương thức static không thể sử dụng từ khóa this hoặc super.

Các tổ hợp thể hiện, phương thức class và biến sau đây là hợp lệ:

  • các phương thức thể hiện có thể truy cập trực tiếp cả các phương thức thể hiện và các biến thể hiện phương pháp cá thể
  • cũng có thể truy cập trực tiếp các biến static và phương thức static
  • các phương thức static có thể truy cập tất cả các biến static và các phương thức static khác
  • các phương thức static không thể truy cập trực tiếp các biến thể hiện và các phương thức thể hiện. Họ cần một số tham chiếu đối tượng để làm như vậy.

Một khối static

Chúng tôi sử dụng một khối static để khởi tạo các biến static. Mặc dù chúng ta có thể khởi tạo các biến static trực tiếp trong khi khai báo, nhưng có những trường hợp chúng ta cần thực hiện xử lý nhiều dòng. Trong những trường hợp như vậy, các khối static có ích.

Nếu các biến static yêu cầu logic nhiều câu lệnh bổ sung trong quá trình khởi tạo, chúng ta có thể sử dụng một khối static.

Ví dụ khối static

Chẳng hạn, giả sử chúng ta muốn khởi tạo một đối tượng Danh sách với một số giá trị được xác định trước.

Điều này trở nên dễ dàng với các khối static:

public class StaticBlockDemo {
    public static List<String> ranks = new LinkedList<>();

    static {
        ranks.add("Lieutenant");
        ranks.add("Captain");
        ranks.add("Major");
    }
    
    static {
        ranks.add("Colonel");
        ranks.add("General");
    }
}

Không thể khởi tạo một đối tượng Danh sách với tất cả các giá trị ban đầu cùng với khai báo. Vì vậy, đây là lý do tại sao chúng tôi đã sử dụng khối static ở đây.

Lý do để sử dụng khối static

Dưới đây là một vài lý do để sử dụng các khối static:

  • nếu việc khởi tạo các biến static cần một số logic bổ sung ngoài việc gán
  • nếu việc khởi tạo các biến static dễ xảy ra lỗi và cần xử lý ngoại lệ

Những điểm chính cần nhớ

Một class có thể có nhiều khối static.

các trường static và các khối static được giải quyết và chạy theo thứ tự giống như chúng hiện diện trong class.

Một class static

Java cho phép chúng ta tạo một class bên trong một class. Nó cung cấp một cách nhóm các phần tử mà chúng ta sẽ chỉ sử dụng ở một nơi. Điều này giúp giữ cho mã của chúng tôi có tổ chức hơn và dễ đọc hơn.

Nói chung, kiến trúc class lồng nhau được chia thành hai loại:

  • các class lồng nhau mà chúng ta khai báo static được gọi là các static nested classes
  • các class lồng nhau không static được gọi là các inner classes

Sự khác biệt chính giữa hai loại này là các class inner có quyền truy cập vào tất cả các thành viên của class kèm theo (bao gồm cả các class riêng), trong khi các class lồng static chỉ có quyền truy cập vào các thành viên static của class bên ngoài.

Trên thực tế, các class lồng static hoạt động chính xác như bất kỳ class cấp cao nhất nào khác, nhưng được đặt trong class duy nhất sẽ truy cập nó, để mang lại sự tiện lợi hơn cho việc đóng gói.

Ví dụ về class static

Cách tiếp cận được sử dụng rộng rãi nhất để tạo các đối tượng đơn lẻ là thông qua một class lồng static:

public class Singleton  {
    private Singleton() {}

    private static class SingletonHolder {
        public static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

Chúng tôi sử dụng phương pháp này vì nó không yêu cầu bất kỳ sự đồng bộ hóa nào và dễ học cũng như triển khai.

Những lý do thuyết phục để sử dụng Inner Class static

Chúng ta hãy xem một vài lý do để sử dụng các class bên trong static trong mã của chúng ta:

  • Class sẽ chỉ được sử dụng ở một nơi làm tăng khả năng đóng gói
  • chúng tôi mang mã đến gần nơi duy nhất sẽ sử dụng nó. Điều này làm tăng khả năng đọc và mã dễ bảo trì hơn.
  • nếu một class lồng nhau không yêu cầu bất kỳ quyền truy cập nào vào các thành viên thể hiện của class kèm theo, thì tốt hơn là nên khai báo nó là static. Bằng cách này, nó sẽ không được ghép nối với class bên ngoài và do đó tối ưu hơn, vì chúng sẽ không yêu cầu bất kỳ bộ nhớ heap hoặc stack nào.

Những điểm chính cần nhớ

Về cơ bản, một static nested class không có quyền truy cập vào bất kỳ thành viên thể hiện nào của class bên ngoài kèm theo. Nó chỉ có thể truy cập chúng thông qua tham chiếu của đối tượng.

các static nested class có thể truy cập tất cả các thành viên static của class kèm theo, bao gồm cả các class riêng.

Đặc tả lập trình Java không cho phép chúng tôi khai báo class cấp cao nhất là static. Chỉ các class bên trong các class (các class lồng nhau) mới có thể được tạo thành static.

Tìm hiểu Lỗi “Non-static variable cannot be referenced from a static context

Thông thường, lỗi này xảy ra khi chúng ta sử dụng biến không static bên trong ngữ cảnh static.

Như chúng ta đã thấy trước đó, các biến static thuộc về class và được tải vào thời điểm tải class. Mặt khác, chúng ta cần tạo một đối tượng để tham chiếu đến các biến không static.

Vì vậy, trình biên dịch Java phàn nàn vì cần có một đối tượng để gọi hoặc sử dụng các biến không static.

Bây giờ chúng ta đã biết nguyên nhân gây ra lỗi, hãy minh họa nó bằng một ví dụ:

public class MyClass { 
    int instanceVariable = 0; 
    
    public static void staticMethod() { 
        System.out.println(instanceVariable); 
    } 
    
    public static void main(String[] args) {
        MyClass.staticMethod();
    }
} 

Như chúng ta có thể thấy, chúng ta đã sử dụng instanceVariable, một biến không static, bên trong phương thức static staticMethod.

Kết quả là chúng ta sẽ gặp lỗi Non-static variable không thể được tham chiếu từ ngữ cảnh static.

Kết luận

Trong bài viết này, chúng ta đã thấy từ khóa static đang hoạt động.

Chúng ta cũng đã thảo luận về lý do và lợi ích của việc sử dụng các trường static, phương thức static, khối static và class bên trong static.

Cuối cùng, chúng tôi đã tìm hiểu nguyên nhân khiến trình biên dịch bị lỗi với lỗi “Biến không static không thể được tham chiếu từ ngữ cảnh static”.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Contact Me on Zalo
Call now