Từ khóa static trong Java chủ yếu được sử dụng để quản lý bộ nhớ. Chúng ta có thể áp dụng từ khóa static với các biến, phương thức, khối và các lớp lồng nhau. static
có vai trò quan trọng trong lập trình Java, đặc biệt trong việc quản lý tài nguyên và hiệu suất của ứng dụng. Cùng tìm hiểu Static trong Java là gì?
Tìm việc làm Java không yêu cầu kinh nghiệm
Static trong Java là gì?
Trong Java, từ khóa static
được sử dụng để xác định rằng một thành viên của lớp (biến hoặc phương thức) thuộc về chính lớp đó, thay vì đối tượng (instance) của lớp. Điều này có nghĩa là thành viên static
có thể được truy cập mà không cần khởi tạo đối tượng.
Chúng ta có thể áp dụng từ khóa static với các biến, các phương thức, các khối, các lớp lồng nhau(nested class).
- Biến static (static variables): khi bạn khai báo một biến là static, thì biến đó được gọi là biến tĩnh, hay biến static.
- Phương thức static (static methods): khi bạn khai báo một phương thức là static, thì phương thức đó gọi là phương thức static.
- Khối static (static blocks): được sử dụng để khởi tạo thành viên dữ liệu static.
- Lớp static (static class): một class được có thể được đặt là static chỉ khi nó là một nested class. Một 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).
- Import static: từ phiên bản Java 5, cho phép import các thành viên tĩnh (static member) của một class hoặc package vào một class khác bằng cách sử dụng từ khóa import và sau đó sử dụng chúng như là thành viên của lớp đó.
Biến static (static variables) trong Java
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 tất cả objects (hoặc instances ) của lớp đó và điều đó giúp cho chương trình tiết kiệm bộ nhớ hơn
Nếu một biến vừa khai báo từ khóa final vừa khai báo từ khóa static thì nó được xem như là một hằng số. Một hằng số nên được viết hoa và nếu có nhiều từ thì phân cách bằng dấu gạch dưới (_)
public static final PI = 3.14;
Trong Interface, mặc định một biến sẽ được khai báo là public static final.
Nếu một biến được khai báo với từ khóa static thì bạn có thể truy cập trực tiếp thông qua lớp.
Ví dụ: Website gpcoder.com có rất nhiều bài viết, mỗi bài viết cần hiển thị địa chỉ của website dưới mỗi bài viết, địa chỉ này giống nhau và có nhiều lớp cần sử dụng. Để tiết kiệm bộ nhớ, dễ dàng chia sẻ và sử dụng ở các lớp khác. Chúng ta có thể sử dụng từ khóa static như sau:
MyWebsite.java
public class MyWebsite { public static String WEBSITE = "gpcoder.com"; }
UsingStaticExample.java
public class UsingStaticExample { private String subject; UsingStaticExample (String subject) { this.subject = subject; } public void print() { System.out.println("Subject = " + subject); System.out.println("Website = " + MyWebsite.WEBSITE); } public static void main(String[] args) { UsingStaticExample ex1 = new UsingStaticExample("Core Java"); ex1.print(); System.out.println("----"); UsingStaticExample ex2 = new UsingStaticExample("Object Oriented Programing"); ex2.print(); } }
Kết quả:
Subject = Core Java Website = gpcoder.com ---- Subject = Object Oriented Programing Website = gpcoder.com
Một ví dụ khác thường hay được sử dụng để minh họa cho việc sử dụng từ khóa static là bộ đếm Counter. Bạn có một website và bạn cần đếm số lượt truy cập vào trang. Bạn viết chương trình như sau:
public class Counter { int count = 0; public Counter() { } public void visit() { count++; this.print(); } public void print() { System.out.println("count = " + count); } public static void main(String[] args) { Counter c1 = new Counter(); c1.visit(); Counter c2 = new Counter(); c2.visit(); Counter c3 = new Counter(); c3.visit(); } }
Kết quả thực thi chương trình trên
count = 1 count = 1 count = 1
Bạn thắc mắc tại sao kết quả ra kỳ vậy, rõ ràng là tôi đã tăng số lượng truy cập lên rồi mà.
Đó là bởi vì, biến count lấy bộ nhớ tại thời điểm tạo đối tượng, mỗi đối tượng sẽ có bản sao của biến instance, nếu biến count được tăng lên, nó sẽ không ảnh hướng đến các đối tượng khác. Vì thế mỗi đối tượng sẽ có giá trị 1 trong biến count.
Như bạn đã thấy ở trên, biến static sẽ lấy bộ nhớ chỉ một lần, nếu bất cứ đối tượng nào thay đổi giá trị của biến static, nó sẽ vẫn ghi nhớ giá trị của nó.
public class Counter { static int count = 0; public Counter() { } public void visit() { count++; this.print(); } public void print() { System.out.println("count = " + count); } public static void main(String[] args) { Counter c1 = new Counter(); c1.visit(); Counter c2 = new Counter(); c2.visit(); Counter c3 = new Counter(); c3.visit(); } }
Kết quả thực thi chương trình trên
count =
1
count =
2
count =
3
Phương thức static (static methods)
Nếu một phương thức được khai báo với từ khóa static thì phương thức đó được gọi là phương thức static.
Một số đặc điểm:
- Một phương thức static thuộc lớp chứ không phải đối tượng của lớp.
- Một phương thức static có thể được gọi mà không cần tạo khởi tạo (instance) của một lớp.
- Phương thức static có thể truy cập biến static và có thể thay đổi giá trị của nó.
- Một phương thức static chỉ có thể gọi một phương thức static khác, không thể gọi được một phương thức non-static.
- Một phương thức static không thể được sử dụng từ khóa this và super.
- Người dùng không thể override (đè) phương thức static trong Java, bởi vì kỹ thuật đè (overriding) phương thức được dựa trên quá trình gán (binding) động khi khi chương trình đang chạy (runtime) và những phương thức static được gán tĩnh trong thời gian biên dịch. Phương thức tĩnh không ràng buộc với thực thể của lớp nên phương thức tĩnh sẽ không thể override (đè).
Khi nào sử dụng từ khóa static cho một phương thức?
- Khi phương thức không phụ thuộc vào trạng thái của đối tượng, nghĩa là không cần sử dụng bất kỳ dữ liệu thành viên nào của đối tượng, mọi thứ được truyền như các tham số (parameter).
- Các phương thức tiện ích là một trường hợp thường được sử dụng nhất trong Java vì chúng có thể được truy cập trực tiếp bằng tên lớp mà không cần tạo bất thể hiện nào. Lớp java.lang.Math là một ví dụ trường hợp sử dụng static method.
- Sử dụng trong các Design Pattern cần truy cập global như Singleton pattern, Factory pattern, …
Ví dụ:
public class UsingStaticExample { private String subject; UsingStaticExample (String subject) { this.subject = subject; } public void print() { System.out.println("Subject = " + subject); System.out.println("Website = " + MyWebsite.WEBSITE); } public static void changeWebsite(String website) { MyWebsite.WEBSITE = website; } public static void main(String[] args) { UsingStaticExample ex1 = new UsingStaticExample("Core Java"); ex1.changeWebsite("abc.com"); ex1.print(); System.out.println("----"); UsingStaticExample.changeWebsite("https://gpcoder.com"); ex1.print(); } }
Kết quả:
Subject = Core Java Website = abc.com ---- Subject = Core Java Website = https://gpcoder.com
Khối static (static blocks)
- Khối static được dùng để khởi tạo hoặc thay đổi giá trị của các biến static.
- 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.
Ví dụ:
public class UsingStaticExample { private static String subject; static { System.out.println("Khối static được gọi"); } static { subject = "Khối static (static blocks)"; } UsingStaticExample () { System.out.println("hàm main() được gọi"); System.out.println("Subject = " + subject); } public static void main(String[] args) { UsingStaticExample ex1 = new UsingStaticExample(); } }
Kết quả:
Khối static được gọi hàm main() được gọi Subject = Khối static (static blocks)
Lớp static (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). Một 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).
Ví dụ:
public class UsingStaticExample { private String subject; UsingStaticExample (String subject) { this.subject = subject; } // nested static class static class MyWebsite { public static String WEBSITE = "gpcoder.com"; } public void print() { System.out.println("Subject = " + subject); System.out.println("Website = " + MyWebsite.WEBSITE); } public static void main(String[] args) { UsingStaticExample ex1 = new UsingStaticExample("Core Java"); ex1.print(); } }
Kết quả:
Subject = Core Java Website = gpcoder.com
Import static trong Java
Java cho phép import các thành viên tĩnh (static member) của một class hoặc package vào một class khác bằng cách sử dụng từ khóa import và sau đó sử dụng chúng như là thành viên của lớp đó.
Ví dụ:
SystemConfig.java
package com.gpcoder; public final class SystemConfig { public static final String USER_NAME = "gpcoder"; public static final String PASSWORD = "123"; public static final String EMAIL = "[email protected]"; private SystemConfig() { } }
StaticImportDemo.java
package com.gpcoder; import static com.gpcoder.SystemConfig.*; public class StaticImportDemo { public static void main(String[] args) { System.out.println("Username: " + USER_NAME); System.out.println("Password: " + PASSWORD); System.out.println("Email: " + EMAIL); } }
Như bạn thấy, khi sử dụng import static chúng ta có thể gọi trực tiếp các thành viên mà không cần phải thông qua tên class, chẳng hạn SystemConfig.USER_NAME
Ứng dụng của static
- Tiết kiệm bộ nhớ: Các biến và phương thức
static
chỉ có một bản sao duy nhất được lưu trong bộ nhớ, do đó giúp tiết kiệm bộ nhớ khi bạn có nhiều đối tượng của lớp sử dụng chung dữ liệu. - Tính toán hoặc tiện ích: Phương thức static thường được sử dụng cho các phương thức tiện ích, chẳng hạn như các phương thức toán học trong lớp
Math
của Java (Math.sqrt()
,Math.abs()
, v.v.). - Đồng nhất dữ liệu: Khi có các biến cần được chia sẻ giữa các đối tượng và không thay đổi giữa các lần sử dụng,
static
là lựa chọn hợp lý để đảm bảo sự đồng nhất của dữ liệu.
Hạn chế của static
- Thiếu tính linh hoạt: Các phương thức static không thể truy cập trực tiếp vào các biến và phương thức non-static, do đó bạn không thể sử dụng chúng khi cần thao tác với dữ liệu cụ thể của từng đối tượng.
- Quá tải bộ nhớ: Mặc dù
static
giúp tiết kiệm bộ nhớ, nhưng nếu không sử dụng đúng cách (ví dụ: quá nhiều biến static), chúng có thể chiếm một lượng bộ nhớ lớn vì luôn tồn tại trong suốt thời gian chạy chương trình.
Sự khác biệt giữa static
và non-static
Tiêu chí | static | non-static |
---|---|---|
Thuộc về | Thuộc về lớp (class-level). | Thuộc về đối tượng (instance-level). |
Truy cập | Có thể truy cập mà không cần tạo đối tượng của lớp. | Phải tạo đối tượng của lớp để truy cập. |
Số lượng bản sao | Chỉ có một bản sao cho tất cả các đối tượng của lớp. | Mỗi đối tượng có bản sao riêng của các biến và phương thức. |
Truy cập biến và phương thức khác | Chỉ có thể truy cập các thành viên static khác trong lớp. | Có thể truy cập cả biến và phương thức static lẫn non-static. |
Một số câu hỏi thường gặp khi đi phỏng vấn liên quan đến từ khóa static
Ý nghĩa của từ khoá static trong Java là gì? Chúng ta có thể override (đè) một hàm private hoặc static trong Java không?
Từ khoá static biểu thị cho biến hoặc phương thức có thể được truy cập (sử dụng) mà không cần tạo ra thực thể của lớp chứa nó. Người dùng không thể override phương thức static trong Java, bởi vì kỹ thuật đè (overriding) phương thức được dựa trên quá trình gán (binding) động khi runtime (khi chương trình đang chạy) và những phương thức static được gán tĩnh trong thời gian biên dịch. Phương thức tĩnh không ràng buộc với thực thể của lớp nên phương thức tĩnh sẽ không thể override.
Chúng ta có thể truy cập một biến không tĩnh (non-static) trong một ngữ cảnh static được không?
Một biến static phụ thuộc vào lớp của nó và giá trị của nó sẽ tồn tại (giữ) cho tất cả các thực thể của lớp đó. Biến static được tạo ra khi lớp chứa đó được tải (load) bởi JVM. Nếu cố gắng truy cập vào một biến non-static (trong hàm static) mà không có trong thực thể (instance) nào thì trình biên dịch sẽ báo lỗi, bởi vì những biến đó (non-static) chưa được khởi tạo và chúng không có ràng buộc với bất kỳ thực thể nào.
Tại sao phương thức main trong Java là static?
Trả lời: Bởi vì không cần thiết phải tạo đối tượng để gọi phương thức static. Nếu nó là phương thức non-static, JVM đầu tiên tạo đối tượng và sau đó gọi phương thức main() mà có thể gây ra vấn đề về cấp phát bộ nhớ bộ nhớ phụ.
Chúng ta có thể thực thi một chương trình mà không có phương thức main()?
Trả lời: Có thể, một trong các cách đó là khối static trong phiên bản trước của JDK 1.7.
Ví dụ:
public class ProgramWithoutMain { static { System.out.println("static block is invoked"); System.exit(0); } }
Kết quả:
Trường hợp chạy ở JDK < 1.7
static block is invoked
Trường hợp chạy ở JDK >= 1.7
Error: Main method not found in class com.gpcoder.ProgramWithoutMain, please define the main method as: public static void main(String[] args) or a JavaFX application class must extend javafx.application.Application
Từ khóa static
trong Java là một công cụ mạnh mẽ để giúp quản lý tài nguyên và hiệu suất của ứng dụng. Nó cho phép chia sẻ dữ liệu và phương thức giữa các đối tượng của một lớp mà không cần khởi tạo chúng mỗi lần. Qua bài viết này, hi vọng đã giúp bạn hiểu về Static và cách sử dụng static
để đảm bảo chương trình của bạn hoạt động hiệu quả.
Nguồn tham khảo: gpcoder.com
Xem thêm các tuyển dụng it hấp dẫn tại TopDev