關於java列舉使用和理解。
前言
在介紹列舉之前,先說說另外一個名詞:[魔法數字]。魔法數字,是指在程式碼中直接出現的數值。
如:user.setStatus(1);
其中的數值1即為[魔法數字],你很難直觀的理解1所代表的含義。至少第一眼,你會疑惑1代表的是什麼。
為了避免這點,在開發時,我想你會添加註釋。
雖然註釋是一件好事情,但是如果程式碼本身就能很好的自說明,我想你一定非常樂意不寫這個註釋。因為它不會讓你有任何心理負擔。
另外有一個想法我覺得不錯:
當你能把程式碼做到很好的抽象時 ——[這時程式碼已經簡潔了不少]
當你在定義方法名/變數名時能做到很好的自說明 ——[這時大部分程式碼,你已經一看就能明白了]
最後,再加上適當的註釋。我想這程式碼,肯定很有藝術感
PS:寫程式碼時,對每一個變數的命名都請仔細思考,慎重。
而我的理解,列舉的誕生就是為了更好的解決上面的問題,提高程式碼的自說明。
另外列舉還有一個非常重要的好處:編譯期間檢查問題,資料的校驗(方法引數定義的使用)等等。
這些在文章後面會一一提到。
言歸正傳
JAVA列舉(enum),JDK 1.5之後引入,存在於java.lang包內。它(enum)與class,interface的地位相同,用來定義列舉類。實際上列舉類是一個特殊的類,它也可以定義自己的方法,屬性,構造器等,甚至可以實現介面。
api文件中,java.lang.Enum描述(大致):
//所有Java語言列舉型別的公共基本類。(注意Enum為抽象類)
public abstract class Enum<E extends Enum<E>>extends Object implements Comparable<E>, Serializable{
......
}
PS:文章最後附錄了完整的java.lang.Enum,有興趣的可以看一看
我們先來定義一個簡單的enum(如下):
public enum Color{
RED,BLUE,BLACK,YELLOW
}
ps:別去追究它為什麼這麼寫,因為這是語法。
它也等價於:
public enum Color{
RED() ,BLUE(),BLACK(),YELLOW();
}
總結:
1.用enum關鍵字來定義列舉類。
2.顯示的列出列舉值(請在第一行就這麼做,並大寫),用逗號隔開。
本質上:Color列舉類位元組碼程式碼(大致):
//注意幾個地方:1.類的修飾為final;2.RED的型別,和修飾詞;
public final class enums.Color extends java.lang.Enum<enums.Color> {
public static final enums.Color RED;
public static final enums.Color BLUE;
public static final enums.Color BLACK;
public static final enums.Color YELLOW;
.........
}
由此可以得出列舉的一些本質:
(1)使用enum定義的列舉類,本質上是class類(我還是想用[有些特殊]來形容),只是它預設直接繼承了java.lang.Enum類。[請把它當作class看待]
(2)列舉值(RED,BLUE…..)本質上是列舉Color物件,並且他們是final修飾的靜態常量。這些值我們一般使用構造器的方式去初始化(後面會提到)。
(3)列舉類的構造器只能使用private訪問控制符,哪怕是隱藏的構造器,它的訪問控制符也是private。
PS:這點也很好理解,當需要我們使用構造器時。
無非是這麼兩種情況:
1.需要建立一個例項;然而列舉裡面的列舉值是靜態的,我們不需要通過建立例項來得到它。
2.需要初始化屬性;我想如果你用列舉,就一定不會去這麼做。因為那是常量並且是final。
(4)使用enum定義非抽象的列舉類預設會使用final修飾。但是(如):當列舉內有抽象方法時,該列舉類即為非抽象列舉類,不會被final修飾,這意味著可以被繼承。(在後面還會提到,如果無法理解請先跳過)。
實際使用:
1.如果需要使用列舉類的某個例項,可以使用“列舉類.某個例項”的形式,例如Color.RED。注意,這裡只是獲取例項。實際使用中,獲取例項只是第一步,後續還有一個取值的過程(後面給大家介紹)。
public class Test {
public static void querColor(Color c) {
switch (c) {
case RED:
System.out.println("我選了紅色");
break;
case BLUE:
System.out.println("我選了藍色");
break;
case BLACK:
System.out.println("我換了黑色");
break;
case YELLOW:
System.out.println("我選了黃色");
break;
}
}
public static void main(String[] args) {
queryColor(Color.RED); //列舉取例項
}
}
JDK1.5增加列舉後對switch也進行了擴充套件,switch的條件表示式可以使用列舉型別。當switch條件表示式使用列舉型別時,case中的值可以直接使用列舉值名字。
2.我們往往在使用列舉時就希望列舉物件(列舉值)是不可變的。即列舉類的所有Field都應該用final修飾(它本身也是這麼做的)。在這裡我們一般使用構造器給這些屬性初始化值。(或者在定義Field時指定預設值,或者在初始化塊中指定初始值,但這兩種情況不推薦)。
在實際開發過程中,我們根據業務需求,在定義列舉類時資料結構都會比Color複雜。如:UserTypeEnum
public enum UserTypeEnum {
ADMINISTRATOR(0, "管理員"), SHOP(2, "門店"), WAITER(1, "小二"), SELLER(3, "銷售");
private Integer code;
private String desc;
private UserTypeEnum(Integer code, String desc){
this.setCode(code);
this.setDesc(desc);
}
public String getDesc() {
return desc;
}
public Integer getCode() {
return code;
}
//**不應該存在set方法。**
}
上面程式中 ADMINISTRATOR(0, “管理員”), SHOP(2, “門店”), WAITER(1, “小二”), SELLER(3, “銷售”),等同於如下程式碼:
//這點非常關鍵
private static final UserTypeEnum ADMINISTRATOR=new UserTypeEnum(0, "管理員");
private static final UserTypeEnum SHOP=new UserTypeEnum(2, "門店"),;
private static final UserTypeEnum WAITER=new UserTypeEnum(1, "小二");
private static final UserTypeEnum SELLER=new UserTypeEnum(3, "銷售");
到了這裡你需要好好理解一下,既然等價於new UserTypeEnum(2, "門店") ...
我想你應該也能明白為什麼需要寫顯示的帶參構造器。
PS:如果列舉值括號內沒有值(理解為呼叫無參構造),是可以省略的。這也很好的解釋了文章開頭:
ADMINISTRATOR 等價於 ADMINISTRATOR()
取值的過程:
UserTypeEnum.SHOP.getDesc() //即能得到"門店"
UserTypeEnum.SHOP.getCode() //即能得到2
這個時候你就會發現,他真的就是一個[普通]的class。是不是很簡單!
3.列舉類也可以實現一個或多個介面。與普通類實現一個或多個介面完全一樣,列舉類實現一個或多個介面時,也需要實現該介面所包含的方法。
public interface PrintColor {
void print();
}
public enum Color implements PrintColor{
RED, BLUE, BLACK, YELLOW;
@Override
public void print() {
System.out.println("print......");
}
}
如果由列舉類來實現接口裡的方法,則每個列舉類(列舉值)物件在呼叫該方法時,都有相同的行為方式(因為方法體完全一樣)。如果需要每個列舉物件在呼叫該方法時,呈現出不同的行為方式,則可以讓每個列舉物件分別來實現該方法。
public interface PrintColor {
void print();
}
public enum Color implements PrintColor {
RED {
@Override
public void print() {
System.out.println("畫紅色!");
}
},
BLUE {
@Override
public void print() {
System.out.println("畫藍色!");
}
},
BLACK {
@Override
public void print() {
System.out.println("畫黑色!");
}
},
YELLOW {
@Override
public void print() {
System.out.println("畫黃色!");
}
};
}
RED、BLUE、BLACK和YELLOW實際上是Color匿名子類的例項,而不是Color類的例項。我的理解是這個時候Color變成了抽象類。
注意:並不是所有的列舉類都使用了final修飾。非抽象的列舉類才預設使用final修飾。對於一個抽象的列舉類而言(只要它包含了抽象方法,它就是抽象列舉類),系統會預設使用abstract修飾,而不是使用final修飾。
每個列舉物件提供不同的實現方式,從而讓不同的列舉物件呼叫該方法時,具有不同的行為方式。
4.如果不使用介面,而是直接在列舉類中定義一個抽象方法,然後再讓每個列舉物件提供不同的實現方式。
public enum Color {
RED {
@Override
public void print() {
System.out.println("畫紅色!");
}
},
BLUE {
@Override
public void print() {
System.out.println("畫藍色!");
}
},
BLACK {
@Override
public void print() {
System.out.println("畫黑色!");
}
},
YELLOW {
@Override
public void print() {
System.out.println("畫黃色!");
}
};
abstract void print();
}
Color是一個包含抽象方法的列舉類,但是“public enum Color”沒有使用abstract修飾,這是因為編譯器(javac)會在編譯生成.class時,自動新增abstract。同時,因為Color包含一個抽象方法,所以它的所有列舉物件都必須實現抽象方法,否則編譯器會報錯。
另外在實際使用中,我們也會用列舉來做其他事情:
比如說,
public void modifyListing(List<Long> itemIds, Long status)
public void modifyListing(List<Long> itemIds, MallItemStatusEnum status)
這兩個方法是同一個方法,只是引數一個用了Long型別的,另一個用了MallItemStatusEnum列舉型別的。
而區別好處:
前者,只要隨便傳一個值都行。事實上如果這麼做,你肯定會在方法裡面做一個校驗,確保這個值不會出現問題。
而後者不需要,最多進行一個判斷status是否為空操作。
附錄:java.lang.Enum
/*
* %W% %E%
*
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package java.lang;
import java.io.Serializable;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
/**
* This is the common base class of all Java language enumeration types.
*
* @author Josh Bloch
* @author Neal Gafter
* @version %I%, %G%
* @since 1.5
*/
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
/**
* The name of this enum constant, as declared in the enum declaration.
* Most programmers should use the {@link #toString} method rather than
* accessing this field.
*/
private final String name;
/**
* Returns the name of this enum constant, exactly as declared in its
* enum declaration.
*
* <b>Most programmers should use the {@link #toString} method in
* preference to this one, as the toString method may return
* a more user-friendly name.</b> This method is designed primarily for
* use in specialized situations where correctness depends on getting the
* exact name, which will not vary from release to release.
*
* @return the name of this enum constant
*/
public final String name() {
return name;
}
/**
* The ordinal of this enumeration constant (its position
* in the enum declaration, where the initial constant is assigned
* an ordinal of zero).
*
* Most programmers will have no use for this field. It is designed
* for use by sophisticated enum-based data structures, such as
* {@link java.util.EnumSet} and {@link java.util.EnumMap}.
*/
private final int ordinal;
/**
* Returns the ordinal of this enumeration constant (its position
* in its enum declaration, where the initial constant is assigned
* an ordinal of zero).
*
* Most programmers will have no use for this method. It is
* designed for use by sophisticated enum-based data structures, such
* as {@link java.util.EnumSet} and {@link java.util.EnumMap}.
*
* @return the ordinal of this enumeration constant
*/
public final int ordinal() {
return ordinal;
}
/**
* Sole constructor. Programmers cannot invoke this constructor.
* It is for use by code emitted by the compiler in response to
* enum type declarations.
*
* @param name - The name of this enum constant, which is the identifier
* used to declare it.
* @param ordinal - The ordinal of this enumeration constant (its position
* in the enum declaration, where the initial constant is assigned
* an ordinal of zero).
*/
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
/**
* Returns the name of this enum constant, as contained in the
* declaration. This method may be overridden, though it typically
* isn't necessary or desirable. An enum type should override this
* method when a more "programmer-friendly" string form exists.
*
* @return the name of this enum constant
*/
public String toString() {
return name;
}
/**
* Returns true if the specified object is equal to this
* enum constant.
*
* @param other the object to be compared for equality with this object.
* @return true if the specified object is equal to this
* enum constant.
*/
public final boolean equals(Object other) {
return this==other;
}
/**
* Returns a hash code for this enum constant.
*
* @return a hash code for this enum constant.
*/
public final int hashCode() {
return super.hashCode();
}
/**
* Throws CloneNotSupportedException. This guarantees that enums
* are never cloned, which is necessary to preserve their "singleton"
* status.
*
* @return (never returns)
*/
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
/**
* Compares this enum with the specified object for order. Returns a
* negative integer, zero, or a positive integer as this object is less
* than, equal to, or greater than the specified object.
*
* Enum constants are only comparable to other enum constants of the
* same enum type. The natural order implemented by this
* method is the order in which the constants are declared.
*/
public final int compareTo(E o) {
Enum other = (Enum)o;
Enum self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}
/**
* Returns the Class object corresponding to this enum constant's
* enum type. Two enum constants e1 and e2 are of the
* same enum type if and only if
* e1.getDeclaringClass() == e2.getDeclaringClass().
* (The value returned by this method may differ from the one returned
* by the {@link Object#getClass} method for enum constants with
* constant-specific class bodies.)
*
* @return the Class object corresponding to this enum constant's
* enum type
*/
public final Class<E> getDeclaringClass() {
Class clazz = getClass();
Class zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? clazz : zuper;
}
/**
* Returns the enum constant of the specified enum type with the
* specified name. The name must match exactly an identifier used
* to declare an enum constant in this type. (Extraneous whitespace
* characters are not permitted.)
*
* @param enumType the <tt>Class</tt> object of the enum type from which
* to return a constant
* @param name the name of the constant to return
* @return the enum constant of the specified enum type with the
* specified name
* @throws IllegalArgumentException if the specified enum type has
* no constant with the specified name, or the specified
* class object does not represent an enum type
* @throws NullPointerException if <tt>enumType</tt> or <tt>name</tt>
* is null
* @since 1.5
*/
public static <T extends Enum<T>> T valueOf(Class<T> enumType,
String name) {
T result = enumType.enumConstantDirectory().get(name);
if (result != null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum const " + enumType +"." + name);
}
/**
* prevent default deserialization
*/
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
throw new InvalidObjectException("can't deserialize enum");
}
private void readObjectNoData() throws ObjectStreamException {
throw new InvalidObjectException("can't deserialize enum");
}
/**
* enum classes cannot have finalize methods.
*/
protected final void finalize() { }
}
相關推薦
關於java列舉使用和理解。
前言 在介紹列舉之前,先說說另外一個名詞:[魔法數字]。魔法數字,是指在程式碼中直接出現的數值。 如:user.setStatus(1); 其中的數值1即為[魔法數字],你很難直觀的理解1所代表的含義。至少第一眼,你會疑惑1代表的是什麼。 為了避免這點,
java列舉和constant使用區別
本文結合《Effective Java》第六章前半部分關於列舉的介紹和自己的理解及實踐,講解了Java列舉的知識點。文章釋出於專欄Effective Java,歡迎讀者訂閱。 前言 你程式碼中的flag和status,都應該用列舉來替代很多人都說,列舉在實際開發中很少用到,甚至就沒用到。因為,他
mongodb 中的 map reduce 的快速入門例子,簡單操作和理解。
先看下mongodb官方給出的例子的圖。 個人理解的解釋: 這個圖,有四列資料。 第一列:原始資料。通常對應的mongodb裡面的一個表collection。 第二列:經過某些條件過濾過的資料,這個圖裡面就是按{"status":"A"}過濾資料。這個過濾的條件對應上面程式
C語言三字棋遊戲先簡單介紹一下三子棋的規則,方便我們接下來的程式設計和理解。規則如下: 在九宮格棋盤上,只要將自己的三個棋子走成一條線(橫、豎、對角線),對方就算輸了。
//判斷輸贏 char IsWin(char arr[ROW][COL], int row, int col) { int i; for (i = 0; i < row; i++) { if (arr[i][0] == arr[i][1] && arr[i][1] == arr
angular 引入編輯器以及控制器的學習和理解。。。
class dex 報錯 callback 1.5.0 ide color 卡住 就是 在angular中引入編輯器的時候花了很長時間,然後發現自己以前根本就沒好好用過angular,因為項目是接手的學姐的,學姐又是接手的學姐的,到我這裏就只是寫寫頁面的事了。 引入編輯器
iOS中類似java抽象類理解。
/** * @author 麥子, 15-09-26 12:09:57 * * 抽象類IOS這邊無法規定子類必須實現一個方法,這邊只是一個警號,編譯依然能過。所以感覺無法控制編寫程式碼的規範。 具體的就是。 通過父類實現對應的協議, 其中必須實現的也就
bootstrap-table 分頁,超細緻!新手寫的個人的看法和理解。
我最近也是剛剛開始寫部落格,目的就是記錄給自己看的。 bootstrap-table 分頁 無意是挺煩的。 網上也有,但是不是那麼簡單。其實我就是一個新人。我也看不懂他們寫的。 <table data-toggle="table" data-mobile-respon
IO流緩衝區物件的使用和理解。
/* 模擬一下 BufferedReader 明白了 BufferedReader 類中特有方法 readLine 的原理後 可以自定義一個類中包含一個功能和 readLine 一樣的方法 */ import java.io.*; class My
1.對Java平臺的理解。“Java是解釋執行”對嗎
Java本身是一種面向物件的語言,最顯著的特性有兩個方面,一是所謂的“書寫一次,到處執行”,能夠非常容易地獲得跨平臺能力; 另外就是垃圾收集(GC),Java通過垃圾收集器(Garbage Collector)回收分配記憶體,大部分情況下,程式設計師不需要自己操心記憶體的分配和回收。 對於“J
小白學JAVA,與你們感同身受,JAVA---day5:關於多型的理解和分析。魯迅的一句話:總之歲月漫長,然而值得等待。
魯迅的一句話:總之歲月漫長,然而值得等待。 至於是不是他說的,就看大家的了。 /* 多型:事物存在的多種形態。 多型的前提: 1.要有繼承關係。 2.要有方法的重寫。 3.要有父類引用指向子類物件。 向上轉型和向下轉型: 1.父類引用指向子類物件 &nbs
【小家Java】深入理解Java列舉型別(enum)及7種常見的用法(含EnumMap和EnumSet)
相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9
談一談我對java單繼承和多繼承的理解。
今天終於重拾書本,感覺好久好久沒有認真看過書了樣。好了不說廢話了。 偶是菜鳥,可能理解有誤。高手們指點指點哦。 今天看那書上說:java是但繼承,並不支援多繼承,後來又講到java支援多繼承,是在介面的基礎上實現多繼承。 總的來說還是不支援多繼承,要通過其他方式來彌補jav
Java列舉型別入門(1)_基礎理解,其他看不懂。
看到視訊,教程解釋不是很詳細。 找的基礎解釋。找到的其他例子都是直接例子,無解釋。。還是這個比較容易看懂。 搬過來。。。 原文:51CTO 我居然從頭看完了。。方便理解 關於引數,也有其他的文章。 Tiger中的一個重要新特性是列舉構造,它是一種新的Java列舉型別,允
java算法面試題:設計一個快速排序。雙路快速排序,簡單易於理解。
面試題 != ava 思路 add bubuko 比較器 繼續 array package com.swift; import java.util.ArrayList; import java.util.Collections; import java.util.Com
記錄一次線程池的在項目中的實際應用,講解一下線程池的配置和參數理解。
div pro 繼續 bstr warn fin autowire string ping 前言:最近項目中與融360項目中接口對接,有反饋接口(也就是我們接收到請求,需要立即響應,並且還要有一個接口推送給他們其他計算結果),推送過程耗時、或者說兩個接口不能是同時返回,有先
java解析和組裝json以及一些方法的理解
content 獲取 con imei title 報錯 bsp ava 取值 這是一個json格式的字符串 第一種情況(簡單格式) String result = "{\"name\":\"小明\",\"age\":\"12\"}";JSONObject json =
java中異常(Exception)的定義,意義和用法。舉例
use 詳情 put 視頻下載 ati itl url index ring 1.異常(Exception)的定義,意義和用法 (視頻下載) (全部書籍) 我們先給出一個例子,看看異常有什麽用? 例:1.1-本章源碼 public class Test { publi
給自己的JAVA工程師學習計劃和路線。
nbsp 結束 調整 了解 enter 如何 但是 毅力 java基礎知識 近來一直在想自己是否能夠在開發方面一直堅持學習下去,如何在JAVA方面能夠取得一點成就,不多說了就是幹。 給自己制定了兩年的短期JAVA學習計劃,堅持就是勝利!希望自己可以在未
列舉類的使用和理解enmu
原始的介面定義常量 public interface IConstants { String MON = "Mon"; String T
關於記憶體地址和記憶體空間的理解。
VIPler 關於記憶體地址和記憶體空間的理解。 1.記憶體地址用4位16進位制和8位16進製表示的區別。例如經常可以看到某些書籍上寫的記憶體地址0x0001,在另外一