枚举简介
枚举值是给域或者方法创建一系列的有效值,枚举内可以单独存在,也可以在某个类中作为内部类。
枚举定义
public enum Test112 {
NUMBER ,
NUMBER1
}
枚举是区分大小写,多个枚举值之间要用逗号隔开,可以写在一行或者多行。
枚举使用
private static Test112 t;
public static void main(String[] args) {
t = Test112.NUMBER;
}
使用枚举中的值就像是用静态类的静态成员一样。首先,你是需要定义这个枚举类型的变量去接收他。
静态final和枚举区别
public class Test111 {
public static final int NUMBER1 = 1;
public static final int NUMBER2 = 2;
}
private static Test112 t;
private static int t1;
public static void main(String[] args) {
t = Test112.NUMBER;
//t = 1;枚举变量只能是枚举值,不可以在赋其他值
t1 = Test111.NUMBER1;
t1 = 3;//而静态final的变量,是可以在进行赋值。
}
如果是通过枚举,枚举类型的变量只能是枚举值的其中一个,并且枚举变量不可以赋其他值。而静态final是可以实现类似枚举的预定义值,但是接收静态final的变量,你注意看,还是根据他的值的基本类型去划分,所以你可以用同种类型值给他赋值。另外,枚举值是一个对象,因此它的行为和对象一样。
枚举类作为类的成员使用
public class Test111 {
private enum type{NUMBER,NUMBER1};
type t = type.NUMBER;
}
遍历枚举类的值
for(<枚举类> t:<枚举类>.values()) {
System.out.println(t.toString());
}
java.lang.Enum类说明
- 没有公开的构造器,也就是说程序员不能构造实例。 其实很容易想明白,所谓枚举类就是有包含有固定数量实例(并且实例的值也固定)的特殊类,如果其含有public构造器,那么在类的外部就可以通过这个构造器来新建实例,显然这时实例的数量和值就不固定了,这与定义枚举类的初衷相矛盾
- 枚举类的每一个实例都是隐式静态,这也就解释了为啥每次调用都是<枚举类>.直接调用。
- 每一个枚举变量只有一个实例。
- ordinal()返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。这个和后面的EnumMap有关。
- 记住,枚举类不可以继承任何类,因为他们只继承 java.lang.Enum,java是单继承。
枚举类中实例是一个对象
当我们枚举中对的实例不是一个简单字段的时候,或者是你定义的字符串的时候,那么这个时候,实例可以是个对象,而这时,一切可以应用到对象上的,都可以用在实例中。
package com.example.test;
public enum Test112 {
number(0,"我是实例0的值"),
number1(1,"我是实例1的值"),
number2(2,"我是实例2的值"),
number3(3,"我是实例3的值");//首先申明了4个实例,我们number(0,"我是实例0的值")看做是一个构造函数,只是类比记忆,那么需要提供一个构造函数是吧(注意虽然构造函数是写在枚举类中,但是不是枚举类的,枚举类没有构造函数,已经强调几遍了),这里的构造函数,只是写在这边以保证实例不会编译出错,在后面测试,你会发现,其实你又不能用这个构造没有意义,但是必须写在这,很多时候,没有那么多为什么!!!!并且这指明这两个参数的字段名。
private int num ;
private String name1;
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
private Test112(int num, String name1) {
this.num = num;
this.name1 = name1;
}
public int getNum() {//暴露出每个属性的get、set方便之后的修改。
return num;
}
public void setNum(int num) {
this.num = num;
}
}
注意:
如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例。
//参考学习https://www.cnblogs.com/happyPawpaw/archive/2013/04/09/3009553.html
测试:
Test112 t2 = Test112.number1;
t2.setNum(5);//通过暴露出的方法,修改值
t2.setName1("我是修改的");
Test112[] t = Test112.values();//values()方法获取每一个实例对象
for(Test112 tt:t) {
System.out.println(tt.getNum()+"*****"+tt.getName1());//
//遍历,通过暴露出的方法,获取实例对应属性的值
}
利用接口组织枚举类
//参考学习https://www.cnblogs.com/happyPawpaw/archive/2013/04/09/3009553.html
public interface Test115 {
enum Coffee implements Test115 {
BLACK_COFFEE, DECAF_COFFEE, LATTE, CAPPUCCINO
}
enum Dessert implements Test115 {
FRUIT, CAKE, GELATO
}
}
使用:
Test115 t = Test115.Coffee.BLACK_COFFEE;
Test115 t1 = Test115.Dessert.FRUIT;
}
通过这个方法,我们可以将多个不同枚举类组织在一起使用。
EnumMap
该类是将Map和Enum的结合使用,将Enum类型的实例,作为Map的键。
由 iterator 方法返回的迭代器按其自然顺序 遍历这些元素(该顺序是声明枚举常量的顺序)
EnumMap小实例
Map<Test112,String> map = new EnumMap<Test112,String>(Test112.class);
//map.put("1","我是枚举map1");根据泛型,这个是不能添加,我们这里规定键是指定枚举类中的实例
map.put(Test112.number1,"sdasa11");
//map.put(null,"sdsada222");
//不允许使用 null 键。试图插入 null 键将抛出 Null
//PointerException。但是,试图测试是否出现 null 键或
//移除 null 键将不会抛出异常。允许使用 null 值。
map.put(Test112.number2,"sdasa33");
map.put(Test112.number3,"sdasa44");
Set<Entry<Test112,String>> s =map.entrySet();//这个方法是获取map中所有映射关系的集合
for(Entry<Test112, String> entry:s) {//遍历所有映射关系
System.out.println(entry.getKey()+"^^^^"+entry.getValue());//拿到每个映射对应的名和值
}
String value = map.get(Test112.number1);
System.out.println(value);
//其原理就是一个对象数组,数组的下标索引就是根据Map中的key
//直接获取,即枚举中的ordinal值;
//效率比HashMap高,可以直接获取数组下标索引并访问到元素;
//参考学习https://www.cnblogs.com/chenpi/archive/2016/03/19/5296330.html
/* 源码 public V get(Object key) {
return (isValidKey(key) ?
unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
}*/
EnumSet
其实就是Set和Enum结合使用,set中的元素都是枚举类的,我们先回忆一下Set,是一个集合,在这个集合中,会自动去除重复元素,并且允许空值,最多一个,不能重复呀。
EnumSet小例子
Set<Test112> s = new HashSet<>();
s.add(Test112.number);
s.add(Test112.number1);
s.add(Test112.number2);
Iterator i = s.iterator();
while(i.hasNext()) {
System.out.println(i.next());
}