CodeGym /Blog Java /Ngẫu nhiên /liệt kê. Ví dụ thực tế. Thêm các hàm tạo và phương thức

liệt kê. Ví dụ thực tế. Thêm các hàm tạo và phương thức

Xuất bản trong nhóm
CHÀO! Hôm nay chúng ta sẽ nói về một trong những kiểu dữ liệu đặc biệt của Java: Enum(viết tắt của "enumeration"). Điều gì làm cho nó đặc biệt? Hãy tưởng tượng những gì chúng ta cần để thực hiện "tháng" trong một chương trình. liệt kê.  Ví dụ thực tế.  Thêm hàm tạo và phương thức - 1 Không có vẻ có vấn đề, phải không? Chúng ta chỉ cần xác định những thuộc tính mà bất kỳ tháng nào có. Có lẽ trước tiên chúng ta cần tên của tháng và số ngày trong đó. Giải pháp trông khá đơn giản:

public class Month {

   private String name;
   private int daysCount;

   public Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public int getDaysCount() {
       return daysCount;
   }

   public void setDaysCount(int daysCount) {
       this.daysCount = daysCount;
   }

   @Override
   public String toString() {
       return "Month{" +
               "name='" + name + '\'' +
               ", daysCount=" + daysCount +
               '}';
   }
}
Toàn bộ shabang! Chúng tôi có một Monthlớp, các trường bắt buộc, getter/setters và toString(). Tất nhiên, trừ khi chúng ta cần thêm equals()hashCode()để đạt được hạnh phúc trọn vẹn :) Nhưng ở đây chúng ta có một vấn đề về khái niệm. Như bạn có thể nhớ, một trong những ưu điểm chính của OOP là nó giúp dễ dàng mô hình hóa các thực thể từ thế giới thực. Một chiếc ghế, một chiếc ô tô, một hành tinh - tất cả những khái niệm này từ cuộc sống bình thường đều dễ dàng được trình bày trong một chương trình với sự trợ giúp của tính trừu tượng. Vấn đề là một số thực thể trong thế giới thực có phạm vi giá trị bị giới hạn nghiêm ngặt. Một năm chỉ có 4 mùa. Chỉ có 8 nốt trong một quãng tám. Lịch chỉ có 12 tháng. Và Danny Ocean của Ocean's 11 chỉ có 11 người bạn (mặc dù điều này không thành vấn đề :)) Điều quan trọng là một lớp Java thông thường không thể mô hình hóa các thực thể này và thực thi các giới hạn tự nhiên của chúng. Của chúng tôiMonthlớp có tất cả các trường bắt buộc. Nhưng nếu một lập trình viên khác sử dụng nó, không ai có thể ngăn anh ta hoặc cô ta tạo ra những đối tượng hoàn toàn điên rồ:

public class Main {

   Month month1 = new Month("lolkek", 322);
   Month month2 = new Month("yahoooooooooooo", 12345);

}
Nếu điều này xuất hiện trong mã của chúng tôi, sẽ không dễ để tìm ra thủ phạm! Một mặt, lập trình viên tạo các đối tượng có thể nhận ra rằng Monthlớp có nghĩa là "tháng trong một năm" và không viết những điều vô nghĩa như vậy. Mặt khác, lập trình viên chỉ tận dụng các khả năng mà người thiết kế lớp cung cấp. Có thể gán tên và số ngày tùy ý không? Đó chính xác là những gì chúng tôi có. Vậy thì chúng ta nên làm gì trong tình huống này? Thành thật mà nói, trước khi Java 1.5 được phát hành, các lập trình viên phải sáng tạo :) Vào thời đó, họ đã tạo ra các cấu trúc như thế này:

public class Month {

   private String name;
   private int daysCount;

   private Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }

   public static Month JANUARY = new Month("January", 31);
   public static Month FEBRUARY = new Month("February", 28);
   public static Month MARCH = new Month("March", 31);

   @Override
   public String toString() {
       return "Month{" +
               "name='" + name + '\'' +
               ", daysCount=" + daysCount +
               '}';
   }
}
Ở đây chúng tôi đã cắt giảm số tháng từ mười hai xuống còn ba để làm cho ví dụ ngắn hơn. Thiết kế như vậy làm cho nó có thể giải quyết vấn đề. Khả năng tạo các đối tượng được giới hạn ở một hàm tạo riêng:

private Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }
Các lập trình viên sử dụng lớp không thể tạo Monthcác đối tượng một cách đơn giản. Họ phải sử dụng các đối tượng tĩnh cuối cùng do nhà phát triển lớp cung cấp. Ví dụ, như thế này:

public class Main {

   public static void main(String[] args) {

       Month january = Month.JANUARY;
       System.out.println(january);
   }

}
Tuy nhiên, các nhà phát triển Java đã thu hút sự chú ý đến vấn đề hiện có. Tất nhiên, thật tuyệt khi các lập trình viên có thể đưa ra giải pháp bằng cách sử dụng các công cụ có sẵn trong ngôn ngữ này, nhưng có vẻ không dễ dàng lắm! Một giải pháp rõ ràng là cần thiết, ngay cả đối với người mới. Và thế là Enumxuất hiện trong Java. Về cơ bản, Enumlà một lớp Java cung cấp một tập hợp giới hạn các giá trị đối tượng. Đây là giao diện của nó:

public enum Month {
  
   JANUARY,
   FEBRUARY,
   MARCH
}
Trong định nghĩa, chúng tôi đã chỉ ra rằng đó Enumlà một lớp Java, nhưng điều đó có thực sự đúng không? Có, và chúng tôi thậm chí có thể xác minh nó. Ví dụ: hãy thử làm cho Monthenum của chúng ta kế thừa một số lớp khác:

public abstract class AbstractMonth {
}

// Error! The extends clause cannot be used with an enum
public enum Month extends AbstractMonth {

   JANUARY,
   FEBRUARY,
   MARCH
}
Tại sao điều đó lại xảy ra? Khi chúng ta viết:

public enum Month
trình biên dịch chuyển câu lệnh này thành đoạn mã sau:

public Class Month extends Enum
Như bạn đã biết, Java không hỗ trợ đa kế thừa. Do đó, chúng tôi không thể kế thừa AbstractMonth. Cấu trúc mới này, Enum, có thể được sử dụng như thế nào? Và nó khác với cấu trúc cũ với static finalcác trường như thế nào? Chà, ví dụ, cấu trúc cũ không cho phép chúng ta sử dụng bộ giá trị của riêng mình trong switchcác câu lệnh. Hãy tưởng tượng rằng chúng tôi muốn tạo một chương trình sẽ nhắc nhở chúng tôi về các ngày lễ được tổ chức hàng tháng:

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           // Error!
           case JANUARY:
       }
   }
}
Như bạn có thể thấy, trình biên dịch đưa ra một lỗi ở đây. Nhưng khi enumđã xuất hiện trong Java 1.5, mọi thứ trở nên đơn giản hơn rất nhiều:

public enum Month {

   JANUARY,
   FEBRUARY,
   MARCH
}

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {
          
           case JANUARY:
               System.out.println("New Year's Day is January 1st!");
               break;
           case FEBRUARY:
               System.out.println("Valentine's Day is February 14th!");
               break;
           case MARCH:
               System.out.println("Saint Patrick's Day is March 17th!");
               break;
       }
   }
}


public class Main {

   public static void main(String[] args) {

       HolidayReminder reminder = new HolidayReminder();
       reminder.printHolidays(Month.JANUARY);

   }

}
Đầu ra bảng điều khiển:

New Year's Day is January 1st!
Lưu ý rằng quyền truy cập vào Enumcác đối tượng vẫn ở trạng thái tĩnh, giống như trước Java 1.5. Chúng ta không cần tạo một Monthđối tượng để truy cập các tháng. Khi làm việc với enums, điều rất quan trọng là đừng quên rằng đó Enumlà một lớp chính thức. Điều này có nghĩa là, nếu cần, bạn có thể định nghĩa các hàm tạo và phương thức trong đó. Ví dụ: trong đoạn mã trước, chúng ta chỉ cần chỉ định các giá trị: THÁNG 1, THÁNG 2, THÁNG 3. Tuy nhiên, chúng ta có thể mở rộng Monthenum như sau:

public enum Month {

   JANUARY("January", 31),
   FEBRUARY("February", 28),
   MARCH("March", 31),
   APRIL("April", 30),
   MAY("May", 31),
   JUNE("June", 30),
   JULY("July", 31),
   AUGUST("August", 31),
   SEPTEMBER("September", 30),
   OCTOBER("October", 31),
   NOVEMBER("November", 30),
   DECEMBER("December", 31);

   private String name;
   private int daysCount;

   Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }

   public static Month[] getWinterMonths() {

       return new Month[]{DECEMBER, JANUARY, FEBRUARY};
   }

   public static Month[] getSummerMonths() {

       return new Month[]{JUNE, JULY, AUGUST};
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public int getDaysCount() {
       return daysCount;
   }

   public void setDaysCount(int daysCount) {
       this.daysCount = daysCount;
   }

   @Override
   public String toString() {
       return "Month{" +
               "name='" + name + '\'' +
               ", daysCount=" + daysCount +
               '}';
   }
}
Ở đây chúng tôi đã cung cấp enum2 trường (tên của tháng và số ngày), một hàm tạo sử dụng các trường này, getter/setters, phương thức toString()và 2 phương thức tĩnh. Như bạn có thể thấy, không có vấn đề gì với điều này. Một lần nữa, Enumthực sự là một lớp chính thức:

import java.util.Arrays;

public class Main {

   public static void main(String[] args) {

       System.out.println(Arrays.toString(Month.getSummerMonths()));

   }

}
Đầu ra bảng điều khiển:

[Month{name='June', daysCount=30}, Month{name='July', daysCount=31}, Month{name='August', daysCount=31}]
Cuối cùng, tôi muốn giới thiệu một cuốn sách cực kỳ hữu ích về Java, đó là "Java hiệu quả" của Joshua Bloch . liệt kê.  Ví dụ thực tế.  Thêm hàm tạo và phương thức - 3Tác giả là một trong những người tạo ra Java, vì vậy bạn hoàn toàn có thể tin tưởng vào lời khuyên của anh ấy về cách sử dụng chính xác và thành thạo các công cụ của ngôn ngữ :) Về bài học của chúng ta, tôi khuyên bạn nên đặc biệt chú ý đến chương của cuốn sách về Enum. Chúc bạn đọc vui vẻ! :)
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION