天天看點

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

一:枚舉類

枚舉是JDK1.5添加的,在枚舉類型出來之前,我們都是以定義常量來代替,比如:

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

這種定義常量的方式也是有一些不足的,如int值相同的情況下,編譯期并不會提示我們的,是以很容易造成混淆。

定義枚舉類的一般文法:任意兩個枚舉成員不能具有相同的名稱,多個枚舉成員之間使用逗号分隔,枚舉表示的類型其取值是必須有限的

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

二:枚舉類原理

把剛才定義的Date枚舉類編譯後再反編譯class檔案來看一下:

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

可以看到,使用關鍵字enum定義的枚舉類型,在編譯期後,也将轉換成為一個實實在在的類,而在該類中,會存在每個在枚舉類型中定義好變量的對應執行個體對象,如上述的ONE枚舉類型對應public static final Date ONE;,同時編譯器會為該類建立兩個方法,分别是values()和valueOf()。

  • 枚舉類實際上也是一個類,預設繼承于java.lang.Enum類,并且此類是final的,不可被繼承,又由于java是單繼承已經預設繼承Enum是以我們定義的Date枚舉類是不允許繼承其他類的。
  • 預設生成私有構造函數,隻能由虛拟機去建立,不允許外部直接建立枚舉類對象的。
  • 定義的枚舉實際上是枚舉類型的常量。

java.lang.Enum源碼

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用
java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

下面例子測試其方法:

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

運作輸出:

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

Values()方法與ValueOf()方法

values()方法和valueOf(String name)方法是編譯器生成的static方法,在Enum類中并沒出現values()方法,但valueOf()方法還是有出現的,隻不過編譯器生成的valueOf()方法需傳遞一個name參數,而Enum自帶的靜态方法valueOf()則需要傳遞兩個方法,其實,編譯器生成的valueOf方法最終還是調用了Enum類的valueOf方法:

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

運作輸出:

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

values()方法的作用就是擷取枚舉類中的所有變量,并作為數組傳回。

valueOf(String name)方法與Enum類中的valueOf方法的作用類似根據名稱擷取枚舉變量。

三:枚舉類使用

  • enum 與 class、interface 具有相同地位,但是不能繼承與被繼承,也不能建立執行個體,隻能由JVM去建立。
  • 可以實作多個接口,也可以擁有構造器、成員方法、成員變量。

實作接口

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

定義構造函數

注意:隻能是私有的構造函數或預設

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

定義成員方法和成員變量

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

EnumMap

java.util.EnumSet和java.util.EnumMap是兩個枚舉集合。EnumMap繼承了AbstractMap類,是以EnumMap具備一般map的使用方法,主要通過一個儲存key的數組K[] keyUniverse和一個儲存value的數組Object[] vals來操作。

源碼:

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用
java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用
java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用
java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

下面例子測試其方法:

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

運作輸出:

{ONE=1, THREE=3}
           

EnumSet

EnumSet是與枚舉類型一起使用的專用 Set 集合,EnumSet 中所有元素都必須是枚舉類型。注意EnumSet不允許使用 null 元素。試圖插入 null 元素将抛出 NullPointerException,但試圖測試判斷是否存在null 元素或移除 null 元素則不會抛出異常,與大多數collection 實作一樣,EnumSet不是線程安全的,是以在多線程環境下應該注意資料同步問題。

public abstract class EnumSet> extends AbstractSet
           
implements Cloneable, java.io.Serializable
           
//元素的class
           
final Class elementType;
           
final Enum>[] universe;
           
private static Enum>[] ZERO_LENGTH_ENUM_ARRAY = new Enum>[0];
           
this.elementType = elementType;
           
this.universe = universe;
           
}
           
//建立一個具有指定元素類型的空EnumSet。
           
Enum>[] universe = getUniverse(elementType);
           
if (universe == null)
           
throw new ClassCastException(elementType + " not an enum");
           
if (universe.length <= 64)
           
return new RegularEnumSet<>(elementType, universe);
           
else
           
return new JumboEnumSet<>(elementType, universe);
           
}
           
//建立一個指定元素類型并包含所有枚舉值的EnumSet
           
EnumSet result = noneOf(elementType);
           
result.addAll();
           
return result;
           
}
           
abstract void addAll();
           
建立一個包含參數容器中的所有元素的EnumSet
           
return s.clone();
           
}
           
return ((EnumSet)c).clone();
           
if (c.isEmpty())
           
throw new IllegalArgumentException("Collection is empty");
           
Iterator i = c.iterator();
           
E first = i.next();
           
EnumSet result = EnumSet.of(first);
           
while (i.hasNext())
           
result.add(i.next());
           
return result;
           
}
           
}
           
// 初始集合包括指定集合的補集
           
EnumSet result = copyOf(s);
           
result.complement();
           
return result;
           
}
           
// 建立一個包括參數中所有元素的EnumSet
           
EnumSet result = noneOf(e.getDeclaringClass());
           
result.add(e);
           
return result;
           
}
           
EnumSet result = noneOf(e1.getDeclaringClass());
           
result.add(e1);
           
result.add(e2);
           
return result;
           
}
           
EnumSet result = noneOf(e1.getDeclaringClass());
           
result.add(e1);
           
result.add(e2);
           
result.add(e3);
           
return result;
           
}
           
EnumSet result = noneOf(e1.getDeclaringClass());
           
result.add(e1);
           
result.add(e2);
           
result.add(e3);
           
result.add(e4);
           
return result;
           
}
           
public static > EnumSet of(E e1, E e2, E e3, E e4,
           
E e5)
           
EnumSet result = noneOf(e1.getDeclaringClass());
           
result.add(e1);
           
result.add(e2);
           
result.add(e3);
           
result.add(e4);
           
result.add(e5);
           
return result;
           
}
           
@SafeVarargs
           
EnumSet result = noneOf(first.getDeclaringClass());
           
result.add(first);
           
for (E e : rest)
           
result.add(e);
           
return result;
           
}
           
// 建立一個包括枚舉值中指定範圍元素的EnumSet
           
if (from.compareTo(to) > 0)
           
throw new IllegalArgumentException(from + " > " + to);
           
EnumSet result = noneOf(from.getDeclaringClass());
           
result.addRange(from, to);
           
return result;
           
}
           
abstract void addRange(E from, E to);
           
@SuppressWarnings("unchecked")
           
return (EnumSet) super.clone();
           
throw new AssertionError(e);
           
}
           
}
           
abstract void complement();
           
Class> eClass = e.getClass();
           
if (eClass != elementType && eClass.getSuperclass() != elementType)
           
throw new ClassCastException(eClass + " != " + elementType);
           
}
           
return SharedSecrets.getJavaLangAccess()
           
.getEnumConstantsShared(elementType);
           
}
           
}
           

下面例子測試其方法:

建立EnumSet并不能使用new關鍵字,因為它是個抽象類,而應該使用其提供的靜态工廠方法,EnumSet的靜态工廠方法比較多,如下:

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用
java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

運作輸出:

java 枚舉_吃透Java基礎十一:枚舉一:枚舉類二:枚舉類原理三:枚舉類使用

繼續閱讀