Tôi đã thực hiện một số thử nghiệm và vô tình viết một mã, điều này rất lạ và tôi không hiểu hết. Tôi thậm chí còn ngạc nhiên rằng tôi có thể biên dịch nó. Nó trông giống như thế này:Java: Định nghĩa các phương pháp và biến bên trong hằng số của enum
enum Foo {
VALUE_1 {
public int myVariable = 1;
},
VALUE_2 {
public void myMethod() {
//
}
},
VALUE_3;
}
Đúng như dự đoán, nó không thể truy cập vào một yếu tố như vậy theo cách sau:
Foo.VALUE_2.myMethod();
Lý do là, trình biên dịch sẽ tìm kiếm phương pháp mà bên trong liệt kê bản thân .
Tôi cho rằng không thể truy cập các phương pháp và biến này từ bên ngoài điều tra. Vì lý do này, tôi đã cố gắng tạo một hàm tạo tham số và gọi nó với một số biến nội bộ:
enum Foo {
VALUE(internalVariable) {
int internalVariable = 1;
};
private Foo(int param) {
//
}
}
Không thể biên dịch một công trình như vậy. Bây giờ tôi đã nghĩ điểm xác định thứ gì đó bên trong hằng số là gì nếu không có cách nào để truy cập nó.
Tôi đã cố tạo các phương thức có cùng tên trong hằng số cũng như trong liệt kê chính nó để kiểm tra xem nó có va chạm theo một cách nào đó không. Nó không được!
enum Foo {
VALUE_1 {
int myVariable = 1;
public int myMethod() {
return myVariable;
}
},
VALUE_2 {
//
};
public int myMethod() {
return 0;
}
}
Và đây là thời điểm vui nhộn! Tôi đã cố gắng thực hiện cuộc gọi của myMethod() trong liệt kê và thực sự đã tìm ra cách thức hoạt động của phép thuật Java này. Các phương thức, được định nghĩa bên trong hằng số, ghi đè các phương thức được xác định bên trong liệt kê.
Foo.VALUE_1.myMethod(); // Returns 1
Foo.VALUE_2.myMethod(); // Returns 0
Tuy nhiên, chúng tôi không thể ghi đè biến, phải không? Vì vậy, tôi đã tò mò, làm thế nào nó hoạt động với các biến chỉ.
enum Foo {
VALUE_1 {
public int myVariable = 1;
},
VALUE_2 {
//
};
public int myVariable = 0;
}
....
System.out.println(Foo.VALUE_1.myVariable); // Returns 0
System.out.println(Foo.VALUE_2.myVariable); // Returns 0
Bây giờ tôi cuối cùng nhận được những câu hỏi của tôi:
Tại sao tôi không nhận được bất kỳ lỗi nếu tôi có thể tạo phương pháp nào bên trong liệt kê liên tục và trái trống mà không phương pháp này? Trong trường hợp đó, phương pháp tôi vừa xác định không thể được gọi là. Hoặc là tôi sai?
Cập nhật: Tôi biết rằng liệt kê có thể triển khai giao diện. Tuy nhiên, nếu tôi không có cụ thể nói rằng, toàn bộ mã là vô nghĩa.
Ai đó đã chỉ ra rằng ngay cả khi không thể truy cập phương thức từ ngôn ngữ theo cách thông thường , vẫn có thể sử dụng phản chiếu. Vâng ... Tại sao chúng tôi không thiết kế một từ khóa không thể truy cập ?
inaccessible void magicalMethod() { // }
Phương thức như vậy sẽ được biên dịch thành tệp * .class. Khi bạn muốn sử dụng nó, bạn phải tự mình tải bytecode và diễn giải nó.
Tôi không thể hiểu được, tại sao có thể xác định phương pháp không thể truy cập. Lý do duy nhất Tôi có thể nghĩ là lập trình viên đang hoạt động và chưa có định nghĩa về giao diện.Vì vậy, anh ấy chỉ đang chuẩn bị mã của các phương thức đơn lẻ và sẽ thêm từ khóa "thực hiện" sau đó. Bên cạnh điều này là vô lý, nó vẫn sẽ yêu cầu phải có một phương pháp như vậy trong tất cả các hằng số.
Tôi nghĩ điều này sẽ kết thúc với lỗi, không chỉ cảnh báo về phương pháp không sử dụng. Bạn có thể quên để thêm mệnh đề "triển khai" hoặc để xác định phương pháp trong điều tra (sẽ là ghi đè) và sẽ nhận ra rằng ngay sau lần sử dụng đầu tiên. Java là ngôn ngữ rất nghiêm ngặt, vì vậy tôi mong đợi hành vi này.
Tại sao tôi không gặp bất kỳ lỗi nào nếu tôi tạo biến công khai (hoặc trường, chính xác hơn) bên trong hằng số? Nó không thể được truy cập trong mọi trường hợp (từ bên ngoài). Do đó, công cụ sửa đổi "công khai" không có ý nghĩa gì ở đây.
Cập nhật: Nó ít giống với điểm trước đó, ngoại trừ khả năng hiển thị công cụ sửa đổi hoàn toàn vô dụng tại đây. Nó thực sự không quan trọng nếu nó được công khai, bảo vệ hoặc riêng tư, bởi vì bạn sẽ không thể truy cập vào đó. Tôi nghi no la một con bọ.
Tại sao nó có thể định nghĩa một lớp (không bổ tầm nhìn), nhưng không giao tiếp? Vâng, bạn có lẽ sẽ không muốn viết liệt kê tàn bạo đến mức bạn sẽ cần định nghĩa các lớp bên trong hằng số và thậm chí là sử dụng thừa kế ở đó. Nhưng nếu có thể định nghĩa các lớp và các lớp trừu tượng thì có vẻ hơi kỳ lạ.
Cập nhật: Đây chắc chắn không phải là thứ bạn cần thường xuyên, nhưng tôi hiểu rằng nó có thể hữu ích. Nhưng tại sao nó chỉ giới hạn ở các lớp và giao diện không thể là cũng được xác định?
enum Foo { VALUE { class MyClass { // OK } abstract class MyAbstractClass { // OK } interface MyInterface { // FAIL. It won't compile. } } }
Bạn có sử dụng chức năng như vậy ở đâu đó không? Tôi có thể tưởng tượng nó có thể hữu ích, nhưng nó hơi khó hiểu. Ngoài ra, khi tôi đang tìm kiếm một số tài nguyên về điều đó, tôi đã không tìm thấy bất cứ điều gì.
Cập nhật: Tôi muốn xem một số ví dụ thực tế được ghi đè bằng phương pháp trong cơ thể lớp liên tục enum. Bạn đã thấy nó trong một số dự án nguồn mở chưa?
Môi trường:
$ java -version
java version "1.7.0_21"
OpenJDK Runtime Environment (IcedTea 2.3.9) (7u21-2.3.9-0ubuntu0.12.10.1)
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)
Cảm ơn thời gian của bạn và cho câu trả lời của bạn!
Bạn có thể tìm thấy ví dụ thực tế về các phương pháp ghi đè bên trong một chi phí enum trong dự án nguồn mở của Nhà máy Maker: http://www.github.com/raspacorp/maker – raspacorp