Khi lập trình, chúng ta thường gặp phải nhu cầu giới hạn tập hợp các giá trị hợp lệ cho một kiểu dữ liệu nhất định. Vì vậy, ví dụ, ngày trong tuần có thể có 7 giá trị khác nhau, tháng trong năm có thể có 12 và mùa có thể có 4. Để giải quyết những vấn đề như vậy, nhiều ngôn ngữ lập trình kiểu tĩnh cung cấp một kiểu dữ liệu đặc biệt - phép liệt kê ( Các thành viên Enum là các thể hiện
Các phần tử
enum
). Việc liệt kê không xuất hiện ngay lập tức trong Java. Cấu trúc ngôn ngữ chuyên biệt enum
đã được giới thiệu bắt đầu từ phiên bản 1.5. Cho đến thời điểm này, các lập trình viên đã sử dụng các phương pháp khác để thực hiện phép liệt kê.
xây dựng enum
Hãy bắt đầu với một ví dụ. Hãy mô tảenum
kiểu dữ liệu để lưu trữ phần bằng cách sử dụng:
enum Season { WINTER, SPRING, SUMMER, AUTUMN }
Vâng, một ví dụ đơn giản về việc sử dụng nó:
Season season = Season.SPRING;
if (season == Season.SPRING) season = Season.SUMMER;
System.out.println(season);
Kết quả là SUMMER sẽ được in ra bảng điều khiển . Tôi nghĩ rằng ví dụ này là hiển nhiên và không cần giải thích.
Enum là một lớp
Bằng cách khai báoenum
, chúng ta ngầm tạo ra một lớp dẫn xuất từ java.lang.Enum
. Thông thường, việc xây dựng enum Season { ... }
tương đương với class Season extends java.lang.Enum { ... }
. Và mặc dù trình biên dịch không cho phép chúng ta kế thừa một cách rõ ràng từ java.lang.Enum
chúng ta, nhưng vẫn dễ dàng xác minh rằng enum
nó được kế thừa bằng cách sử dụng reflection
:
System.out.println(Season.class.getSuperclass());
Sau đây sẽ được hiển thị trên bảng điều khiển:
class java.lang.Enum
Việc kế thừa thực tế được trình biên dịch Java tự động thực hiện cho chúng ta. Tiếp theo, hãy đồng ý gọi lớp do trình biên dịch tạo ra để thực hiện phép liệt kê là enum
-class, và các giá trị có thể có của kiểu liệt kê là enum
các phần tử -a.
Các thành viên Enum là các thể hiện enum
của một -class có thể truy cập tĩnh
Các phần tử enum Season (WINTER, SPRING и т.д.)
là các phiên bản có thể truy cập tĩnh enum
của -class Season
. Tính khả dụng tĩnh của chúng cho phép chúng tôi thực hiện so sánh bằng cách sử dụng toán tử so sánh tham chiếu ==
. Ví dụ:
Season season = Season.SUMMER;
if (season == Season.AUTUMN) season = Season.WINTER;
Tên và số sê-ri của phần tử enum
Như đã đề cập trước đó, bất kỳenum
-class nào cũng kế thừa java.lang.Enum
, chứa một số phương thức hữu ích cho tất cả các kiểu liệt kê. Ví dụ:
Season season = Season.WINTER;
System.out.println("season.name()=" + season.name() + " season.toString()=" + season.toString() + " season.ordinal()=" + season.ordinal());
Đầu ra sẽ là:
season.name()=WINTER season.toString()=WINTER season.ordinal()=0
Các phương pháp name()
và toString()
được hiển thị ở đây ordinal()
. Ngữ nghĩa của các phương pháp là rõ ràng. Cần lưu ý rằng các phương thức này enum
được kế thừa từ lớp java.lang.Enum
. Lấy một phần tử enum
bằng cách biểu diễn chuỗi tên của nó Khá thường xuyên nảy sinh nhiệm vụ lấy một phần tử enum
bằng cách biểu diễn chuỗi của nó. Với những mục đích này, trong mỗi enum
lớp, trình biên dịch sẽ tự động tạo một phương thức tĩnh đặc biệt: public static EnumClass valueOf(String name)
, phương thức này trả về một phần tử liệt kê EnumClass
có tên bằng name
. Ví dụ sử dụng:
String name = "WINTER";
Season season = Season.valueOf(name);
Kết quả của việc thực thi mã, biến mùa sẽ bằng Season.WINTER
. Xin lưu ý rằng nếu không tìm thấy phần tử, ngoại lệ IllegalArgumentException sẽ được ném ra và nếu nó name
bằng nhau null
, ngoại lệ NullPointerException sẽ được ném ra . Nhân tiện, điều này thường bị lãng quên. Vì lý do nào đó, nhiều người tin chắc rằng nếu một hàm nhận một đối số và trong những điều kiện nhất định ném ra IllegalArgumentException thì khi chuyển nó đến đó , IllegalArgumentExceptionnull
chắc chắn cũng sẽ được ném ra . Nhưng đó không phải là vấn đề. Tiếp tục đi. Lấy tất cả các phần tử của một bảng liệt kê Đôi khi bạn cần lấy danh sách tất cả các phần tử của một -class trong thời gian chạy. Với những mục đích này, trình biên dịch sẽ tạo một phương thức trong mỗi lớp -class . Ví dụ sử dụng: enum
enum
public static EnumClass[] values()
System.out.println(Arrays.toString(Season.values()));
Chúng tôi nhận được kết quả đầu ra sau:
[WINTER, SPRING, SUMMER, AUTUMN]
Lưu ý rằng cả phương thức valueOf()
lẫn phương thức đều không values()
được định nghĩa trong lớp java.lang.Enum
. Thay vào đó, chúng được trình biên dịch tự động thêm vào khi enum
lớp - được biên dịch. Thêm các phương thức của riêng bạn vào enum
-class Bạn có cơ hội thêm các phương thức của riêng mình vào cả enum
-class và các phần tử của nó: Tương tự, nhưng có tính đa hình: Ví dụ cuối cùng minh họa việc sử dụng tính kế thừa trong enum
. Thêm về điều này sau. Tính kế thừaenum
trong Java enum
cho phép bạn triển khai hệ thống phân cấp lớp, các đối tượng của nó được tạo trong một phiên bản duy nhất và có thể truy cập tĩnh. Trong trường hợp này, các phần tử enum
có thể chứa hàm tạo của riêng chúng. Hãy đưa ra một ví dụ: Ở đây chúng tôi khai báo một bảng liệt kê Type
có ba phần tử INT
và INTEGER
. STRING
Trình biên dịch sẽ tạo các lớp và đối tượng sau:
Type
- lớp bắt nguồn từjava.lang.Enum
INT
- đối tượng của lớp 1 bắt nguồn từType
INTEGER
- đối tượng của lớp 2 bắt nguồn từType
STRING
- đối tượng của lớp thứ 3 bắt nguồn từType
Object parse(String)
và hàm tạo Type(..., boolean)
. Đồng thời, các đối tượng của lớp INT
và tồn tại trong một bản sao duy INTEGER
nhất STRING
và có thể truy cập tĩnh. Bạn có thể xác minh điều này:
System.out.println(Type.class);
System.out.println(Type.INT.getClass() + " " + Type.INT.getClass().getSuperclass());
System.out.println(Type.INTEGER.getClass() + " " + Type.INTEGER.getClass().getSuperclass());
System.out.println(Type.STRING.getClass() + " " + Type.STRING.getClass().getSuperclass());
Chúng tôi nhận được kết quả đầu ra sau:
class Type
class Type$1 class Type
class Type$2 class Type
class Type$3 class Type
Có thể thấy trình biên dịch đã tạo ra một lớp Type
và 3 nested
lớp dẫn xuất từ Type
.
Lớp enum được dịch ngược có tính kế thừa
Để khẳng định điều trên, chúng tôi cũng trình bày kết quả dịch ngược bảng liệt kêType
từ ví dụ trên:
Bảng liệt kê và đa hình tham số
Có thể bạn đọc sẽ thắc mắc: " Tại sao kiểu liệt kê Type ở trên không sử dụng generics? " Thực tế là trong Java việc sử dụng thuốc generic bịenum
cấm. Vì vậy, ví dụ sau sẽ không biên dịch:
enum Type<T> {}
Học cao hơn
Để hiểu sâu hơn về cách hoạt động của bảng liệt kê trong Java, tôi khuyên bạn nên tự làm quen với mã nguồn của lớpjava.lang.Enum
và cũng sử dụng trình dịch ngược Jad để nghiên cứu mã được tạo. Hơn nữa, việc nghiên cứu mã nguồn thư viện Java là hoàn toàn cần thiết để hiểu có bao nhiêu cơ chế trong Java hoạt động và rất hữu ích như một tài liệu tham khảo cho thiết kế hướng đối tượng. Link nguồn gốc: http://alexander.lds.lg.ua/
GO TO FULL VERSION