JavaRush /Java 博客 /Random-ZH /Java 中的枚举。实际例子。添加构造函数和方法

Java 中的枚举。实际例子。添加构造函数和方法

已在 Random-ZH 群组中发布
你好!今天我们要讲的是Java中一种特殊的数据类型—— Enum(枚举的简称)。他们的特点是什么?让我们想象一下我们需要在该计划中实施几个月。 枚举。 实际例子。 添加构造函数和方法 - 1如此看来,问题出在哪里呢?您只需要确定任何月份都有哪些属性。也许我们首先需要月份的名称和月份的天数。问题的解决方案看起来很简单:
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 +
               '}';
   }
}
请全套!我们有一个类Month,必要的字段,getters-setters toString(),。除非equals()hashCode()需要添加它以获得完全的幸福:)但是,我们有一个概念问题。您可能还记得,OOP 的主要优点之一是它可以轻松地对现实世界的实体进行建模。一把椅子、一辆汽车、一个星球——所有这些日常生活中的概念都可以很容易地在程序中使用抽象来表示。问题在于现实世界中的某些实体的含义范围受到严格限制。一年只有4个季节。音乐只有7个音符。日历上只有12个月。Ocean 只有 11 个朋友(尽管这是有争议的:))换句话说,常规 Java 类无法对这些实体进行建模并尊重它们的自然约束。我们班Month拥有所有必要的领域。但如果另一个程序员使用它,没有人会阻止他创建完全疯狂的对象:
public class Main {

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

}
如果程序中出现这样的情况,想要找到罪魁祸首就不容易了!一方面,创建对象的程序员可以理解该类Month意味着“一年中的月份”,而不会写出这样的废话。另一方面,他只是利用了职业设计师提供给他的机会。我可以指定任何名称和天数吗?他任命了它。遇到这种情况怎么办?在 Java 语言 1.5 版本发布之前,坦率地说,程序员必须摆脱它:) 在那些日子里,他们创建了以下结构:
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("Январь", 31);
   public static Month FEBRUARY = new Month("Февраль", 28);
   public static Month MARCH = new Month("Март", 31);

   @Override
   public String toString() {
       return "Month{" +
               "name='" + name + '\'' +
               ", daysCount=" + daysCount +
               '}';
   }
}
在这里,我们将月份数简化为三个月,而不是十二个月,以使示例更简短。这样的设计使得解决这个问题成为可能。创建对象的选项受到私有构造函数的限制:
private Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }
使用该类的程序员不能简单地创建Month. 他们被迫使用类开发人员提供的那些最终静态对象。它看起来像这样:
public class Main {

   public static void main(String[] args) {

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

}
然而,Java 开发人员注意到了一个现有的问题。当然,很高兴程序员能够使用该语言中提供的工具提出解决方案,但它看起来并不那么简单!我们需要一个显而易见的解决方案,即使是初学者也可以使用。这就是 . 在 Java 中的出现方式Enum。本质上,Enum它是一个提供一组有限值对象的 Java 类。它看起来是这样的:
public enum Month {

   JANUARY,
   FEBRUARY,
   MARCH
}
在定义中,我们指出Enum这是一个 Java 类,但这真的是这样吗?是的,我们甚至可以检查它。例如,尝试enum Month从其他类继承我们的类:
public abstract class AbstractMonth {
}

//ошибка! No extends clause allowed to enum
public enum Month extends AbstractMonth {

   JANUARY,
   FEBRUARY,
   MARCH
}
为什么会发生这种情况?当我们写入程序时:
public enum Month
编译器将此命令转换为如下代码:
public Class Month extends Enum
如您所知,Java 中不允许多重继承。因此,AbstractMonth我们无法继承。如何Enum使用这个新设计?它与旧的带字段的设计有何不同static final?嗯,例如,旧的设计不允许我们在switch-表达式中使用我们自己的一组值。想象一下,我们想要创建一个程序来提醒我们本月庆祝哪些假期:
public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           //error!
           case JANUARY:
       }
   }
}
正如您所看到的,编译器在这里抛出了一个错误。但Java 1.5出现之后enum,一切都变得简单多了:
public enum Month {

   JANUARY,
   FEBRUARY,
   MARCH
}

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           case JANUARY:
               System.out.println("7 января будет Рождество!");
               break;
           case FEBRUARY:
               System.out.println("В феврале празднуется День Защитника Отечества - 23 февраля!");
               break;
           case MARCH:
               System.out.println("В марте отмечается Всемирный Женский День - 8 марта!");
               break;
       }
   }
}



public class Main {

   public static void main(String[] args) {

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

   }

}
控制台输出:

7 января будет Рождество!
请注意:对对象的访问Enum保持静态,就像 Java 1.5 之前一样。我们不需要创建一个对象Month来访问月份。当使用枚举时,不要忘记Enum这是一个成熟的类,这一点非常重要。这意味着,如果需要,您可以在其中定义构造函数和方法。例如,在前面的代码中我们简单地指定了值JANUARY、FEBRUARY、MARCH。但是,我们可以enum Month这样扩展:
public enum Month {

   JANUARY("Январь", 31),
   FEBRUARY("Февраль", 28),
   MARCH("Март", 31),
   APRIL("Апрель", 30),
   MAY("Май", 31),
   JUNE("Июнь", 30),
   JULY("Июль", 31),
   AUGUST("Август", 31),
   SEPTEMBER("Сентябрь", 30),
   OCTOBER("Октябрь", 31),
   NOVEMBER("Ноябрь", 30),
   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 +
               '}';
   }
}
在这里,我们添加了 2 个字段enum- 月份名称和天数、使用这些字段的构造函数、getters-setters、方法toString()以及 2 个静态方法。正如您所看到的,这没有任何问题:正如我们之前所说,enum这是一个成熟的类:
import java.util.Arrays;

public class Main {

   public static void main(String[] args) {

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

   }

}
控制台输出:

[Month{name='Июнь', daysCount=30}, Month{name='Июль', daysCount=31}, Month{name='Август', daysCount=31}]
最后,我想向您推荐一本关于Java非常有用的书,即Joshua Bloch的《Effective Java》枚举。 实际例子。 添加构造函数和方法 - 3作者是 Java 的创建者之一,因此您绝对可以相信他关于正确且有效地使用语言工具的建议:) 关于我们的讲座,我建议您特别注意本书中专门讨论enum. 祝您阅读愉快!:)
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION