Тип перечисления является частью новых функций в Java 5. Это особый тип данных. Причина особенная, потому что он одновременно является типом класса и имеет более специальные ограничения, чем типы классов, но эти ограничения Существование типа перечисления также создает простота, безопасность и удобство.
△Некоторые места до конца не изучены, и я продолжу изучать и дорабатывать эту статью позже.
1. Обучение класса перечисления
1.1 Определение класса перечисления
- Класс перечисления может реализовывать один или несколько интерфейсов.Класс перечисления, определенный enum, по умолчанию наследует класс java.lang.Enum, а не класс Object по умолчанию, поэтому класс перечисления не может явно наследовать другие родительские классы. Класс java.lang.Enum реализует два интерфейса: java.lang.Serializable и java.lang.Comparable. Неабстрактные классы перечисления, определенные с помощью enum, будут завершены по умолчанию, поэтому классы перечисления не могут быть производными от подклассов.
- Конструктор класса перечисления может использовать только частный контроллер доступа.Если контроллер доступа конструктора опущен, по умолчанию используется частный модификатор, если контроллер доступа является обязательным, может быть указан только частный модификатор.
- Все экземпляры класса перечисления должны быть явно перечислены в первой строке класса перечисления, иначе класс перечисления никогда не создаст экземпляр. При перечислении этих экземпляров система автоматически добавит публичное статическое окончательное оформление без необходимости их явного добавления программистами.
- Класс перечисления по умолчанию предоставляет метод values(), который может легко проходить все значения перечисления.
Определим константы с понедельника по воскресенье следующим образом.
//Day.class
//枚举类型,使用关键字enum
enum Day {
MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
Короче говоря, ключевое слово, которое мы используем при определении типа перечисления, — это enum, которое похоже на ключевое слово class, за исключением того, что первое определяет тип перечисления, а второе определяет тип класса.
1.2 Принцип реализации класса перечисления
После того, как мы получили общее представление об определении и простом использовании типов перечисления, теперь необходимо понять основные принципы реализации типов перечисления. на самом деле используя ключевое словоenum
После создания типа перечисления и компиляции компилятор сгенерирует для нас родственный класс, этот класс наследуетJava API
серединаjava.lang.Enum
class, то есть через ключевое словоenum
Создание типа перечисления на самом деле является типом класса после компиляции, и класс наследуется отjava.lang.Enum
своего рода.
Посмотрите декомпилированный файл Day.class:
//反编译Day.class
final class Day extends Enum
{
//编译器为我们添加的静态的values()方法
public static Day[] values()
{
return (Day[])$VALUES.clone();
}
//编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
public static Day valueOf(String s)
{
return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);
}
//私有构造函数
private Day(String s, int i)
{
super(s, i);
}
//前面定义的7种枚举实例
public static final Day MONDAY;
public static final Day TUESDAY;
public static final Day WEDNESDAY;
public static final Day THURSDAY;
public static final Day FRIDAY;
public static final Day SATURDAY;
public static final Day SUNDAY;
private static final Day $VALUES[];
static
{
//实例化枚举实例
MONDAY = new Day("MONDAY", 0);
TUESDAY = new Day("TUESDAY", 1);
WEDNESDAY = new Day("WEDNESDAY", 2);
THURSDAY = new Day("THURSDAY", 3);
FRIDAY = new Day("FRIDAY", 4);
SATURDAY = new Day("SATURDAY", 5);
SUNDAY = new Day("SUNDAY", 6);
$VALUES = (new Day[] {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
});
}
}
- ①Из декомпилированного кода видно, что компилятор помог нам сгенерировать класс Day (обратите внимание, что это класс final и не будет унаследован), и этот класс наследуется от
java.lang.Enum
class, который является абстрактным классом (позже мы разберем основные методы этого класса). - ② Кроме того, компилятор также помог нам сгенерировать 7 экземпляров объектов типа Day, соответствующих 7 датам, определенным в перечислении, что полностью объясняет, что каждый из типов Day, которые мы определили ранее с помощью ключевого слова enum. Константа перечисления даты также является реальный объект экземпляра Day, но содержимое отличается. Обратите внимание, что компилятор также генерирует для нас два статических метода, а именно
values()和 valueOf()
. - ③На данный момент мы также понимаем, что тип перечисления, определенный с помощью ключевого слова enum, также будет преобразован в реальный класс после периода компиляции, и в этом классе будет каждый тип перечисления в типе перечисления.Определите соответствующий объект экземпляра переменной, как указано выше
MONDAY
Соответствие типам перечисленияpublic static final Day MONDAY;
, и компилятор создаст для класса два метода:values()和valueOf()
. На данный момент я считаю, что наш принцип реализации перечисления относительно ясен. Давайте более подробно рассмотрим класс java.lang.Enum и назначение функций values() и valueOf().
1.3 Общие методы подсчета
2. Использование классов перечисления
2.1 Константы
Существует три способа реализации констант в системе: константы интерфейса, константы класса и константы перечисления.
2.1.1 Константы интерфейса
Например, в качели java есть SwingConstant:
public interface SwingConstants {
/**
* The central position in an area. Used for
* both compass-direction constants (NORTH, etc.)
* and box-orientation constants (TOP, etc.).
*/
public static final int CENTER = 0;
//
// Box-orientation constant used to specify locations in a box.
//
/**
* Box-orientation constant used to specify the top of a box.
*/
public static final int TOP = 1;
/**
* Box-orientation constant used to specify the left side of a box.
*/
public static final int LEFT = 2;
//。。。省略其他代码
}
2.1.2 Константы класса
Метод написания (1) Плюсы и минусы: При использовании значения DefaultValues.DEFAULT_AP вы должны прочитать аннотации в классе, чтобы знать, что он представляет собой центр. Если констант много, то ставить все константы в этот интерфейс не очень дружелюбно.
/**
* 系统默认值
*
*/
public class DefaultValues {
/**
* 默认密码
*/
public static final String DEFAULT_PASSWORD = "000000";
/**
* 默认用户类型
*/
public static final String DEFAULT_USER_TYPE = UserType.NormalUser.value();
/**
* 默认获取api名称
*/
public static final String DEFAULT_API = "api";
/**
* 默认系统字符编码
*/
public static final String DEFAULT_ENCODING = "UTF-8";
/**集群规模*/
public static final long CLUSTER_SIZE = 1000;
}
Метод написания (2) Плюсы и минусы: Константы интерфейса компании представляют собой статические внутренние классы, определенные в интерфейсе, которые могут дополнительно классифицировать константные классы различных функций. Константы разных функций помещаются во внутренний класс интерфейса, и значение константы может быть ясно известно через разные внутренние классы.
public class Constants {
public static class MimeType{
public static final String BIN = "application/octet-stream";
public static final String CSS = "text/css";
public static final String DOC = "application/msword";
public static final String DOCX = "";
public static final String EXE = "application/octet-stream";
public static final String GTAR = "application/x-gtar";
public static final String GZ = "application/x-gzip";
public static final String HTM = "text/html;charset=utf-8";
public static final String ICO = "image/x-icon";
public static final String JPEG = "image/jpeg";
public static final String JPG = "image/jpeg";
public static final String JS = "application/x-javascript;charset=utf-8";
public static final String JSON = "application/json;charset=utf-8";
public static final String FORM = "application/x-www-form-urlencoded; charset=UTF-8";
public static final String MULTIPART = "multipart/form-data; charset=UTF-8";
public static final String MHT = "message/rfc822";
public static final String MHTML = "message/rfc822";
public static final String MOV = "video/quicktime";
public static final String MP3 = "audio/mpeg";
public static final String MPE = "video/mpeg";
public static final String MPEG = "video/mpeg";
public static final String MPG = "video/mpeg";
public static final String PDF = "application/pdf";
public static final String PPT = "application/vnd.ms-powerpoint";
public static final String RTF = "application/rtf";
public static final String SWF = "application/x-shockwave-flash";
public static final String TAR = "application/x-tar";
public static final String TXT = "text/plain;charset=utf-8";
public static final String WAV = "audio/x-wav";
public static final String XML = "text/xml;charset=utf-8";
public static final String ZIP = "application/zip";
}
public static class DataState{
public static final String FLAG_REMOVE = "Y";
public static final String FLAG_NORMAL = "N";
}
/**
* 应用服务器实例运行状态
*/
public static class ServerASInstanceState{
public static final int RUNNING = 1;
public static final int SHUT_OFF = 2;
}
/**
* WebServices接口分析
*/
public static class WebServicesType{
/**先接收数据,在返回接口情况的接口 **/
public static final String IN_OUT = "IO";
/**先发数据请求,后返回数据的接口 **/
public static final String OUT_IN = "OI";
/**只发送数据的接口**/
public static final String OUT= "O";
/**只接收数据的接口 **/
public static final String IN = "I";
}
/**
* 任务调度使用
*/
public static class TaskScheduling{
/**任务ID **/
public static final String TASK_ID = "taskID";
/**任务URL **/
public static final String TASK_URI = "taskURI";
/**任务URL **/
public static final String TASK_NAME = "taskName";
/**任务目标服务器IP **/
public static final String TASK_SERVER_IP = "taskServerIp";
/**任务目标服务器IP **/
public static final String TASK_SERVER_PORT = "taskServerPort";
/**任务状态启用**/
public static final int TASK_ENABLED = 1;
/**任务状态禁用**/
public static final int TASK_DISABLE = 0;
/**每年任务**/
public static final int TYPE_EVERY_YEAR= 1;
/**每月任务**/
public static final int TYPE_EVERY_MONTH = 2;
/**每日任务**/
public static final int TYPE_EVERY_DAY = 3;
/**每周任务**/
public static final int TYPE_EVERY_WEEK = 4;
/**单次任务**/
public static final int TYPE_SINGLE = 5;
}
}
Хотя есть перечисление, это может быть связано с привычкой дизайнера, и есть много констант классов, используемых людьми.Map<Integer, String>
Чтобы инкапсулировать информацию, соответствующую константе, вstatic
В блоке кода put выполняется при инициализации класса. когда используешьResponseCode.RESP_INFO.get("DATABASE_EXCEPTION");
Информацию об ответе можно вынести.Так как проект отделен от фронта и бэкенда, код состояния нужно прописать в интерфейсном документе, а также прописать подсказку, соответствующую коду состояния.Кроме того, наш ответ Класс RespInfo имеет атрибут сообщения, который заключается в сохранении кода состояния в константе класса соответствующей информации.
public class ResponseCode {
/** 系统处理正常 */
public static final int SUCCESS_HEAD = 0;
/** 系统处理未知异常 */
public static final int EXCEPTION_HEAD = 1;
/** JSON解析错误 */
public static final int JSON_RESOLVE = 2;
/** 类型不匹配 */
public static final int TRANSTYPE_NO = 3;
/** Head - messageID未赋值 */
public static final int HEAD_messageID = 4;
/** Head - timeStamp未赋值 */
public static final int HEAD_timeStamp = 5;
/** Head - messengerID未赋值 */
public static final int HEAD_messengerID = 6;
/** Head - transactionType 未赋值 */
public static final int HEAD_transactionType = 7;
/** digest校验不通过 */
public static final int HEAD_DIGEST = 8;
/** src校验不通过 */
public static final int HEAD_SRC_NULL = 10;
/** 协议包含非法字符 */
public static final int ILLEGAL_MESSAGE = 11;
/** 数据库异常 */
public static final int DATABASE_EXCEPTION = 9;
public static final Map<Integer, String> RESP_INFO = new HashMap<Integer, String>();
static {
// Head 相关
RESP_INFO.put(SUCCESS_HEAD, "系统处理正常");
RESP_INFO.put(EXCEPTION_HEAD, "系统处理未知异常");
RESP_INFO.put(JSON_RESOLVE, "JSON解析错误");
RESP_INFO.put(TRANSTYPE_NO, "类型不匹配");
RESP_INFO.put(HEAD_messageID, "messageID未赋值");
RESP_INFO.put(HEAD_timeStamp, "timeStamp未赋值");
RESP_INFO.put(HEAD_messengerID, "messengerID未赋值");
RESP_INFO.put(HEAD_transactionType, "transactionType未赋值");
RESP_INFO.put(HEAD_DIGEST, "digest校验不通过");
RESP_INFO.put(DATABASE_EXCEPTION, "数据库异常");
RESP_INFO.put(HEAD_SRC_NULL, "src未赋值");
RESP_INFO.put(ILLEGAL_MESSAGE, "协议包含非法字符");
}
}
2.1.3 Константы перечисления
Все классы перечисления являются подклассами класса Enum, как и класс Object, но они не написаны, поэтому классы перечисления могут вызывать методы Enum. Обратите внимание, что атрибуты разделяются запятыми.Только если после атрибута нет метода, вы можете добавить точку с запятой или нет в конце.
Письмо (1)
public enum StateType {
/**
* 成功返回状态
*/
OK(200,"OK"),
/**
* 请求格式错误
*/
BAD_REQUEST(400,"bad request"),
/**
* 未授权
*/
UNAUTHORIZED(401,"unauthorized"),
/**
* 没有权限
*/
FORBIDDEN(403,"forbidden"),
/**
* 请求的资源不存在
*/
NOT_FOUND(404,"not found"),
/**
* 该http方法不被允许
*/
NOT_ALLOWED(405,"method not allowed"),
/**
* 请求处理发送异常
*/
PROCESSING_EXCEPTION(406,"Handling Exceptions"),
/**
*
* 请求处理未完成
*/
PROCESSING_UNFINISHED(407,"To deal with unfinished"),
/**
* 登录过期
*/
BEOVERDUE(408,"Be overdue"),
/**
* 用户未登录
*/
NOT_LOGIN(409,"Not logged in"),
/**
* 这个url对应的资源现在不可用
*/
GONE(410,"gone"),
/**
* 请求类型错误
*/
UNSUPPORTED_MEDIA_TYPE(415,"unsupported media type"),
/**
* 校验错误时用
*/
UNPROCESSABLE_ENTITY(422,"unprocessable entity"),
/**
* 请求过多
*/
TOO_MANY_REQUEST(429,"too many request");
private int code;
private String value = null;
private StateType(int code,String value) {
this.code = code;
this.value = value;
}
public String value() {
return this.value;
}
public int getCode() {
return code;
}
public static Boolean isValidateStateType(String... stateType) {
for (int i = 0; i < stateType.length; i++) {
StateType [] value = StateType.values();
boolean falg = false;
for(StateType type : value) {
if(type.value.equals(stateType[i])) {
falg = true;
}
}
if(!falg) {
return falg;
}
}
return true;
}
}
/*使用*/
public static void main(String[] args) {
System.out.println("状态码:"+StateType.getCode());
System.out.println("错误信息:"+StateType.getValue());
}
Письмо (2)
public enum Level {
/**
* 第一层
*/
One(1),
/**
* 第二层
*/
Two(2),
/**
* 第三层
*/
Three(3),
/**
* 第四层
*/
Four(4),
/**
* 第五层
*/
Five(5);
private int value;
Level(int value) {
this.value = value;
}
public int value() {
return this.value;
}
public static Boolean isValidateLevel(int level) {
Level [] value = Level.values();
boolean falg = false;
for (Level pl : value){
if(pl.value == level){
falg = true;
}
}
return falg;
}
}
/*使用*/
public static void main(String[] args) {
System.out.println("楼层:"+Level.Three);
}
2.2 переключатель в сочетании с классом перечисления
Оператор switch до JDK1.6 поддерживает только типы int, char и enum.Использование перечисления может сделать наш код более читабельным.
Перечисление — это объявление набора именованных констант.Когда переменная имеет несколько возможных значений, ее можно определить как тип перечисления. Перечисление заключается в перечислении значений переменных одно за другим, а значения переменных ограничены диапазоном перечисленных значений.
△ Примечание:Перечисления — это просто типы перечислений, и им нельзя присваивать назначения. следующее:GREEN默认值为0
,ноGREEN不能=0
, потому что типы данных разные. Переменные в перечислении не назначаются напрямую, значение по умолчанию равно предыдущему значению переменной плюс один, а значение по умолчанию равно 0.
enum Signal {
GREEN, YELLOW, RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch (color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}
2.3 Добавление новых методов в перечисление
Если вы планируете настроить свои собственные методы, вы должны добавить точку с запятой (";") в конце последовательности экземпляров enum.В java вы должны сначала определить экземпляр java.
public enum ChannelEnum {
MSG_CENTER_CHANNEL1("msg_center_channel1"),
MSG_CENTER_CHANNEL("msg_center_channel");
private String channel = null;
private ChannelEnum(String channel) {
this.channel = channel;
}
public String getChannel() {
return this.channel;
}
}
2.4 Реализация интерфейса
- Все перечисления наследуются от класса java.lang.Enum. Поскольку Java не поддерживает множественное наследование, объекты перечисления больше не могут наследоваться от других классов.
- Если метод в интерфейсе реализован классом перечисления, каждое значение перечисления будет вести себя одинаково при вызове метода (поскольку тело метода точно такое же). Если вам нужно, чтобы каждое значение перечисления вело себя по-разному при вызове метода, вы можете сделать так, чтобы каждое значение перечисления реализовывало метод отдельно, каждое значение перечисления предоставляло другую реализацию, чтобы разные значения перечисления Values вели себя по-разному при вызове этого метода.
public interface Behaviour {
void print();
String getInfo();
}
public enum Color implements Behaviour{
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
//接口方法
@Override
public String getInfo() {
return this.name;
}
//接口方法
@Override
public void print() {
System.out.println(this.index+":"+this.name);
}
}
2.5 Организация перечислений с интерфейсами
public interface Food {
enum Coffee implements Food{
BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO
}
enum Dessert implements Food{
FRUIT, CAKE, GELATO
}
}
Оригинальный адрес данных: