Sử dụng static trong Java mang lại một số lợi ích:
1. Chia sẻ tài nguyên:
Biến static và phương thức static thuộc về lớp, chứ không phải đối tượng cụ thể. Điều này có nghĩa là chúng được chia sẻ giữa tất cả các đối tượng của lớp, giúp tối ưu hóa sử dụng bộ nhớ và tránh lãng phí tài nguyên.
public class SharedResourceExample { private static int sharedCounter = 0; public static void incrementCounter() { sharedCounter++; } public static int getSharedCounter() { return sharedCounter; }
}
Trong ví dụ này, biến sharedCounter là biến static, nó được chia sẻ giữa tất cả các đối tượng của lớp SharedResourceExample.
2. Truy cập dễ dàng:
Phương thức và biến static có thể được truy cập trực tiếp từ lớp mà không cần tạo đối tượng. Điều này thuận tiện khi bạn muốn sử dụng chúng mà không cần tạo một đối tượng mới.
public class MathUtility { public static int add(int a, int b) { return a + b; }
}
Phương thức add ở đây là một phương thức utility, và bạn có thể gọi nó trực tiếp từ lớp MathUtility mà không cần tạo một đối tượng MathUtility. Khi bạn không sử dụng từ khóa "static", bạn cần tạo một đối tượng mới để gọi các phương thức không tĩnh trong lớp đó.
3. Khởi tạo một lần:
Biến static có thể được khởi tạo chỉ một lần, thông qua khối static, đảm bảo rằng các giá trị được thiết lập chỉ một lần và duy trì cho toàn bộ thời gian chạy của ứng dụng. public class ConfigurationManager { private static String configFile;
static { configFile = "config.properties"; // Các bước khởi tạo cấu hình chỉ thực hiện một lần
} public static String getConfigFile() { return configFile;
}
}
Trong ví dụ này, giá trị của biến configFile được khởi tạo chỉ một lần trong khối static, đảm bảo rằng cấu hình được thiết lập một lần và giữ nguyên trong toàn bộ thời gian chạy của ứng dụng.
4. Phương thức utility:
public class StringUtils { public static boolean isNullOrEmpty(String str) { return str == null || str.trim().isEmpty(); }
}
Phương thức static thường được sử dụng để triển khai các chức năng utility, không phụ thuộc vào trạng thái của đối tượng cụ thể. Điều này giúp tạo ra các tiện ích toàn cục và dễ tái sử dụng.
Trong trường hợp của phương thức isNullOrEmpty(), không cần tạo đối tượng StringUtils là hợp lý vì phương thức này không tương tác với trạng thái (state) của đối tượng. Nó chỉ nhận một chuỗi đầu vào và trả về kết quả kiểm tra. Do đó, việc khai báo phương thức là tĩnh giúp cho việc sử dụng phương thức trở nên thuận tiện và trực tiếp từ lớp StringUtils mà không cần tạo đối tượng.
5. Hằng số:
public class Constants { public static final int MAX_RETRY_ATTEMPTS = 3; public static final String DEFAULT_LANGUAGE = "en";
}
Biến static thường được sử dụng để định nghĩa hằng số toàn cục mà không cần tạo đối tượng.
Trong Java, từ khóa static khi được sử dụng với final để định nghĩa hằng số, có nghĩa là hằng số đó thuộc về lớp, chứ không phải đối tượng cụ thể. Điều này có một số ưu điểm:
-
Truy cập dễ dàng: Với hằng số static, bạn có thể truy cập chúng trực tiếp từ lớp mà không cần tạo một đối tượng của lớp đó. Điều này giúp giảm độ phức tạp và làm cho mã nguồn dễ đọc hơn.
-
Chia sẻ giữa tất cả các đối tượng: Vì hằng số static thuộc về lớp, nó chỉ được lưu trữ một lần trong bộ nhớ, không phụ thuộc vào số lượng đối tượng được tạo ra từ lớp đó. Điều này giúp giảm bớt lãng phí bộ nhớ khi có nhiều đối tượng được tạo ra.
-
Không thể thay đổi: Hằng số final là các biến không thể thay đổi, giúp đảm bảo rằng giá trị của chúng không bao giờ bị thay đổi trong quá trình thực thi.
Mặc dù static mang lại nhiều lợi ích như đã mô tả trước đó, nhưng cũng có một số bất lợi:
-
Khả năng kiểm thử giảm đi: Đối tượng và biến static có thể làm giảm khả năng kiểm thử vì chúng có thể tạo ra sự phụ thuộc toàn cầu và gây khó khăn trong việc kiểm thử đơn vị (unit testing). Đối tượng và biến không static thì có thể được đặt vào trong môi trường kiểm thử mà không gây tác động lớn đến các phần khác của hệ thống.
-
Khả năng xung đột: Sử dụng quá nhiều biến và phương thức static có thể dẫn đến khả năng xung đột (race conditions) trong môi trường đa luồng, vì chúng được chia sẻ giữa tất cả các luồng thực thi.
-
Quản lý trạng thái khó khăn: Biến static giữ trạng thái của lớp, không phải của đối tượng cụ thể. Điều này có thể làm cho quản lý trạng thái trở nên phức tạp, đặc biệt khi cần theo dõi và quản lý nhiều trạng thái trong ứng dụng lớn.
-
Khả năng gây lạc quan hóa: Sử dụng quá nhiều biến và phương thức static có thể dẫn đến việc thiết kế mã nguồn không tốt, với sự lạc quan hóa (tight coupling) và khả năng chia sẻ tài nguyên global quá mức, làm giảm khả năng mở rộng và bảo trì.
-
Thách thức trong việc kiểm soát truy cập: Biến static có thể được truy cập từ bất kỳ đâu trong mã nguồn, điều này có thể làm tăng khả năng lỗi và khó kiểm soát quyền truy cập.
Ví dụ:
public class AnotherCounter { private static int count = 0; public static void increment() { count++; } public static int getCount() { return count; }
} public class Main { public static void main(String[] args) { Counter.increment(); System.out.println("Counter Count: " + Counter.getCount()); AnotherCounter.increment(); System.out.println("AnotherCounter Count: " + AnotherCounter.getCount()); }
}
Ở đây, mỗi lớp có một biến static count, nhưng chúng không phản ánh chính xác số lượng của đối tượng cụ thể. Điều này có thể dẫn đến hiểu lầm và làm giảm tính linh hoạt của mã nguồn.
Trong trường hợp như vậy, thay vì sử dụng static, ta nên sử dụng biến trạng thái không tĩnh và tạo ra một đối tượng để theo dõi trạng thái của từng đối tượng cụ thể.
POPPIN KHIEM MOHAMED