十九章:枚举类型


一、Enum类源码

public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {
   //枚举实例常量名
    private final String name;
   //返回定义的枚举实例声明的次序,从0开始
    private final int ordinal;  
    public final String name() {
        return name;
    }  
    public final int ordinal() {
        return ordinal;
    }
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }
	public String toString() {
        return name;
    }
	public final boolean equals(Object other) {
        return this==other;
    }
	public final int hashCode() {
        return super.hashCode();
    }
   
    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }

	//针对于枚举类型将获得枚举类,其他类型调用该方法将获得上一级父类
    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }
    
    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 constant " + enumType.getCanonicalName() + "." + name);
    }
}

二、enum基本特性

创建enum时,编译器会为你生成一个相关的类,这个类继承自java.lang.Enum

1.枚举类型T不可被继承(public final class T extends Enum )
2.T中所有属性都被 static final 修饰,天然支持多线程(public static final T SPRING;)

1、方法

ordinal():返回按enum实例声明的次序,从0开始。
values():按enum中声明的顺序返回enum实例数组。
compareTo():比较大小,按enum实例申明顺序进行比较
getDeclaringClass():返回enum实例所属的类,即当前枚举类。
name():返回enum实例声明时的名字
valueOf():根据给定的名字返回相应的enum实例,如果不存在给定名字的实例,将会抛出异常

案例

enum Shrubbery { GROUND, CRAWLING, HANGING}

public class EnumClass {
  public static void main(String[] args) {
    for(Shrubbery s : Shrubbery.values()) {
      print(s + " ordinal: " + s.ordinal());
      printnb(s.compareTo(Shrubbery.CRAWLING) + " ");
      printnb(s.equals(Shrubbery.CRAWLING) + " ");
      print(s == Shrubbery.CRAWLING);
      print(s.getDeclaringClass());
      print(s.name());
      print("----------------------");
    }
    // Produce an enum value from a string name:
    for(String s : "HANGING CRAWLING GROUND".split(" ")) {
      Shrubbery shrub = Enum.valueOf(Shrubbery.class, s);
      print(shrub);
    }
  }
}

运行结果:

GROUND ordinal: 0
-1 false false
class Shrubbery
GROUND
----------------------
CRAWLING ordinal: 1
0 true true
class Shrubbery
CRAWLING
----------------------
HANGING ordinal: 2
1 false false
class Shrubbery
HANGING
----------------------
HANGING
CRAWLING
GROUND

2、静态导入

import static enumerated.Spiciness.*;//静态导入enum类,直接使用enum实例

3、向enum中添加新方法

1、除了不能继承自一个enum之外(本身继承了Enum类,单继承多实现),可以看做一个常规类,可以自定义方法
2、enum定义顺序必须是先enum实例,分号然后在方法
3、enum的构造器和普通class一样,构造器的访问权限只能是包权限或private,其实都一样,因为其构造只能在enum内部使用其构造。
4、enum的方法支持覆盖

public enum OzWitch {
  // 实例必须先于方法定义
  WEST("Miss Gulch, aka the Wicked Witch of the West"),
  NORTH("Glinda, the Good Witch of the North"),
  EAST("Wicked Witch of the East, wearer of the Ruby " + "Slippers, crushed by Dorothy's house"),
  SOUTH("Good by inference, but missing");
  // 构造器只能是包权限或private
  private OzWitch(String description) {
    this.description = description;
  }
  private String description;
  public String getDescription() { return description; }
  @Override// 覆盖enum toString方法
  public String toString() {
    String name = name();
    String lowerCase = name.substring(1).toLowerCase();
    return name.charAt(0)+ lowerCase;
  }

  public static void main(String[] args) {
    for(OzWitch witch : OzWitch.values())
      System.out.println(witch + ": " + witch.getDescription());
  }
}

运行结果:

West: Miss Gulch, aka the Wicked Witch of the West
North: Glinda, the Good Witch of the North
East: Wicked Witch of the East, wearer of the Ruby Slippers, crushed by Dorothy's house
South: Good by inference, but missing

4、switch语句中的enum实例

会自动调用ordinal()方法获取int的enum实例次序。

enum Signal { GREEN, YELLOW, RED, }

public class TrafficLight {
  Signal color = Signal.RED;
  public void change() {
    switch(color) {
      // Note that you don't have to say Signal.RED
      // in the case statement:
      case RED:    color = Signal.GREEN;
                   break;
      case GREEN:  color = Signal.YELLOW;
                   break;
      case YELLOW: color = Signal.RED;
                   break;
    }
  }
  public String toString() {
    return "The traffic light is " + color;
  }
  public static void main(String[] args) {
    TrafficLight t = new TrafficLight();
    for(int i = 0; i < 7; i++) {
      print(t);
      t.change();
    }
  }
}

运行结果:

The traffic light is RED
The traffic light is GREEN
The traffic light is YELLOW
The traffic light is RED
The traffic light is GREEN
The traffic light is YELLOW
The traffic light is RED

5、values() 的神秘之处

编译器自动添加static方法 values和valueOf方法(一个参数)

三、使用接口组织枚举

由于枚举类是无法被继承,然而又想进行分组,只能在一个接口内部创建实现该接口的枚举,进行分组

public interface Food {
  enum Appetizer implements Food {
    SALAD, SOUP, SPRING_ROLLS;
  }
  enum MainCourse implements Food {
    LASAGNE, BURRITO, PAD_THAI, LENTILS, HUMMOUS, VINDALOO;
  }
  enum Dessert implements Food {
    TIRAMISU, GELATO, BLACK_FOREST_CAKE,FRUIT, CREME_CARAMEL;
  }
  enum Coffee implements Food {
    BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,LATTE, CAPPUCCINO, TEA, HERB_TEA;
  }
}
public enum Course {
  APPETIZER(Food.Appetizer.class),
  MAINCOURSE(Food.MainCourse.class),
  DESSERT(Food.Dessert.class),
  COFFEE(Food.Coffee.class);
  private Food[] values;
  //每一个Course实例都通过如下构造器创建
  private Course(Class<? extends Food> kind) {
    values = kind.getEnumConstants();//class的方法获取当前枚举的
  }
  public Food randomSelection() {
    return Enums.random(values);
  }
} 
public class Meal {
  public static void main(String[] args) {
    for(int i = 0; i < 2; i++) {
      for(Course course : Course.values()) {
        Food food = course.randomSelection();
        System.out.println(food);
      }
      System.out.println("---");
    }
  }
} 

运行结果:

SPRING_ROLLS
VINDALOO
FRUIT
DECAF_COFFEE
---
SOUP
VINDALOO
FRUIT
TEA
---

四、使用Enum替代标志

1、EnumSet得成员唯一,但是只能查询、速度和HashSet比很快
2、EnumSet,是为了通过enum创建一种替代品,以替代传统的基于int的“位标志”。这些标志可以用来表示某种“开/关”信息
3、EnumSet的基础是long,当超过64个元素时,会增加一个long

五、EnumMap

1、EnumMap是一种特殊的Map,它要求其中的键(key)必须来自一个enum
2、EnumMap内部有数组构造,允许程序员改变值对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值