Nhiều lập trình viên gặp thông báo lỗi 'Non static method cannot be referenced from a static context' khi họ đang lập trình. Thông báo lỗi này không cụ thể và có thể xảy ra trong bất kỳ IDE nào nếu điều kiện gây ra lỗi là đúng.
Phương thức tĩnh (Static Method) là gì?
Thêm từ khóa 'static' vào bất kỳ phương thức nào sẽ làm cho phương thức đó được gọi là phương thức tĩnh. Phương thức tĩnh thuộc về lớp thay vì thuộc về một đối tượng (đây là quy chuẩn). Phương thức tĩnh có thể được gọi dễ dàng mà không cần điều kiện tạo một thể hiện (instance) của lớp.
Có một số cách sử dụng khác nhau của phương thức tĩnh, ví dụ, sử dụng nó, bạn có thể thay đổi một thành viên dữ liệu tĩnh và giá trị của nó. Tuy nhiên, vẫn còn một số hạn chế khi sử dụng phương thức tĩnh. Ví dụ, nếu bạn muốn truy cập các trường không tĩnh của lớp, bạn phải sử dụng phương thức không tĩnh. Tóm lại, các phương thức tĩnh được sử dụng rất ít nhưng chúng có lợi ích của chúng.
Dưới đây là một ví dụ ngắn về cách phương thức tĩnh có thể được tạo để thay đổi thuộc tính của tất cả các đối tượng.
class Students{
int roll_no;
String name;
static String college = "InformationTech";
static void change(){
college = "Management";
}
Students (int number, String name_self){
roll_no = number;
name = name_self;
}
void display (){
System.out.println(rollno+" "+name+" "+college);
}
public static void main(String args[]){
Students.change();
Students stu_1 = new Students (100,"Mexican");
Students stu_2 = new Students (202,"American");
Students stu_3 = new Students (309,"British");
stu_1.display();
stu_2.display();
stu_3.display();
}
}
Đầu ra của chương trình sẽ là:
100 Mexican Management 202 American Management 309 British Management
Sự khác biệt giữa một lớp (class) và thể hiện của lớp (instance of a class)?
Hãy tưởng tượng bạn đang đi trên đường và thấy một chiếc xe. Bạn ngay lập tức biết rằng đây là một chiếc xe ngay cả khi bạn không biết mẫu hoặc loại của nó. Điều này là vì bạn biết rằng nó thuộc về 'lớp' của 'xe hơi' mà bạn đã biết. Hãy nghĩ về lớp ở đây như một mẫu hoặc một ý tưởng.
Khi bạn đi gần hơn, bạn thấy mẫu và hãng của chiếc xe. Ở đây bạn đang nhận ra 'thể hiện' của 'lớp xe'. Ở đây tất cả các thuộc tính sẽ hiện diện chi tiết; bánh xe, mã lực, jante v.v.
Một ví dụ về thuộc tính có thể là lớp 'xe hơi' quy định rằng tất cả các xe đều phải có bánh xe. Chiếc xe bạn đang thấy (một thể hiện của lớp xe) có jante hợp kim.
Trong lập trình hướng đối tượng, bạn tự định nghĩa lớp và bên trong lớp, bạn định nghĩa một trường kiểu 'màu sắc'. Bất cứ khi nào lớp được khởi tạo, bộ nhớ sẽ tự động được dành riêng cho màu sắc ở backend và sau đó bạn có thể gán cho nó một giá trị cụ thể (ví dụ đỏ). Vì các thuộc tính như thế này là cụ thể, chúng là non-static (không tĩnh).
Ngược lại, các phương thức và trường tĩnh được chia sẻ với tất cả các thể hiện. Chúng được tạo ra cho các giá trị hoặc mục cụ thể cho lớp chứ không phải cho thể hiện bản thân. Đối với phương thức, có thể có các phương thức toàn cục (ví dụ, bộ chuyển đổi stringtoInt) và đối với trường, chúng thường là hằng số theo mã của bạn (ví dụ, loại xe có thể là tĩnh nếu bạn chỉ sản xuất xe bình thường).
Bây giờ, chúng ta sẽ xem tất cả các trường hợp khác nhau mà mã của bạn có thể sai và xem các giải pháp để khắc phục chúng.
Vấn đề 1: Bạn đang gọi thứ gì đó không tồn tại
Chúng tôi gặp một số trường hợp người dùng đang sử dụng cả phương thức tĩnh và không tĩnh với nhau. Khi chúng ta làm điều này, bạn nên cẩn thận về phương thức nào đang gọi phương thức nào (về mặt tĩnh hay không). Hãy xem mã sau:
private java.util.List<String> someMethod(){
/* Some Code */
return someList;
}
public static void main(String[] strArgs){
// Câu lệnh sau gây ra lỗi. Bạn biết tại sao..
java.util.List<String> someList = someMethod();
}
Ở đây, phương thức tĩnh đang gọi someMethod. Trong lập trình hướng đối tượng, chúng ta gói gọn dữ liệu cùng với dữ liệu mà chúng ta muốn thao tác. Ở đây, nếu không có đối tượng, không có dữ liệu thể hiện và trong khi các phương thức thể hiện tồn tại như một phần của định nghĩa lớp, luôn phải có một thể hiện đối tượng để cung cấp dữ liệu cho chúng.
Tóm lại, bạn không thể gọi thứ gì đó không tồn tại. Vì bạn có thể chưa tạo đối tượng, phương thức non-static chưa tồn tại. Tuy nhiên, ngược lại, phương thức tĩnh sẽ luôn tồn tại (do định nghĩa).
Vấn đề 2: Các phương thức không được làm tĩnh
Nếu bạn đang gọi các phương thức từ phương thức main tĩnh của bạn mà không tạo thể hiện của các phương thức, bạn sẽ nhận được thông báo lỗi. Ở đây, cùng nguyên tắc áp dụng; bạn không thể truy cập thứ gì đó không tồn tại.
public class BookStoreApp2 {
//constants for options
Scanner input = new Scanner (System.in);
public static void main(String[] args) {
BookStoreItem[] item;//declaring array
item = new BookStoreItem[10];//initializing array
int itemType = -1;
printMenu();
getUserChoice();
for (int i = 0; i < item.length; i++){
}//end of switch statement
}//end of for loop
for (int i = 0; i < item.length; i++) {
}//end of for
}//end of main method
Ở đây trong mã này, bạn cần chuyển đổi cả hai phương thức printMenu() và getUserChoice() thành các phương thức tĩnh.
Do đó, nếu bạn muốn vượt qua tình huống như thế này, bạn có thể sử dụng constructor thay thế. Ví dụ, bạn có thể lấy nội dung của phương thức main() và đặt chúng bên trong một constructor.
public BookStoreApp2() {
// Put contents of main method here
}
Sau khi làm điều này, hãy làm như sau bên trong phương thức main():
public void main( String[] args ) {
new BookStoreApp2();
}
Nếu các mẹo này không hoạt động cho bạn hoặc mã của bạn khác, bạn nên ghi nhớ các nguyên tắc cơ bản của các lớp và phương thức tĩnh và kiểm tra lại mã của bạn để đảm bảo nguyên tắc cơ bản không bị vi phạm.