Java_常量和枚举(8)

接口常量

在接口中定义的字段在编译时会自动加上 static final 的修饰符,即定义了接口常量

1
2
3
4
5
public interface Grade {
  String A = "优";
  String B = "良";
  String C = "差";
}
1
2
3
4
5
public class Test {  
  public static void main(String[] args){  
    System.out.println(Grade.A);  
  }  
}  

如果业务逻辑发生了变化,需要修改 Grade 中的常量,则使用了 Grade.A 的 Test 类也需要进行重新编译,并且如果有子类实现了 Grade 接口,则接口中定义的所有常量都将暴露出来不管是否需要,破坏了封装性,所以这种定义常量的方式虽然简单直接,但不是特别优雅

类常量

将常量放入 class 类中定义,私有化构造函数,通过调用属性的 get 方法来获取常量值

1
2
3
4
5
6
7
8
9
public class Grade {
  private Grade() {};
  private static final String A = "优";
  private static final String B = "良";
  private static final String C = "差";
  public static String getA() { return A;}
  public static String getB() { return B;}  
  public static String getC() { return C;}  
}
1
2
3
4
5
public class Test {  
  public static void main(String[] args){  
    System.out.println(Grade.getA());  
  }  
}  

此时 Test 类调用的是 Grade 的 getA 方法,如果常量值发生了变化,不需要重新再进行编译了

enum

JDK1.5 引入了枚举 enum ,定义一个简单枚举

1
2
3
4
5
6
7
public class Test {
  public static void main(String[] args) {
    System.out.println(Grade.A.name());    //A
    System.out.println(Grade.A.ordinal()); //0
  }
}
enum Grade {A, B, C}

Grade 会被编译为 class Grade extends Enum<Grade> ,但是源码不能直接这么写

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Grade extends Enum<Grade> { 
  //返回存储枚举实例的数组的副本,values()方法通常用于for遍历
  public static final Grade[] values() { 
    return (Grade[]) $VALUES.clone(); 
  } 
  //根据枚举实例名获取对应的枚举实例
  public static Grade valueOf(String name) { 
    return (Grade) Enum.valueOf(Grade, s);
  }
  //构造方法
  private Grade(String s, int i) {
    super(s, i); 
  }
  //定义枚举对象的引用
  public static final Grade A; 
  public static final Grade B; 
  public static final Grade C;

  //定义用于存放枚举对象的数组的引用
  private static final Grade $VALUES[];

  //在static静态块中调用默认的构造方法创建枚举对象
  static { 
    A = new Grade("A", 0); 
    B = new Grade("B", 1); 
    V = new Grade("C", 2); 
    //将所有常量对象存放在数组中
    $VALUES = (new Grade[] {A, B, C}); 
  } 
}

定义一个复杂枚举,例如订单状态 OrderStatusEnum

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Test {
  public static void main(String[] args) {
    System.out.println(OrderStatusEnum.codeOf(0).getValue());
  }
}

enum OrderStatusEnum {
  //可以给定义的枚举实例添加自定义的字段,对应有默认的ordinal值0,1,2,3
  CANCELED(0, "已取消"),
  NO_PAY(10, "未支付"),
  PAID(20, "已付款"),
  SHIPPED(30, "已发货");

  //要添加自定义字段就需要定义对应的构造方法,重载默认的构造方法
  OrderStatusEnum(int code, String value) {
    this.code = code;
    this.value = value;
  }
  //对应的属性
  private int code;
  private String value;
  //对应的get方法
  public int getCode() {
    return code;
  }
  public String getValue() {
    return value;
  }
  //根据code值返回对应的枚举实例
  public static OrderStatusEnum codeOf(int code) {
    for (OrderStatusEnum o : values()) {
      if (o.getCode() == code) {
        return o;
      }
    }
    return null;
  }
}

通过 enum 关键字定义的枚举类其实都是 abstract class Enum<E extends Enum<E>> 抽象类的子类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {
  protected Enum(String name, int ordinal) {
    this.name = name;
    this.ordinal = ordinal;
  }
  private final String name;
  private final int ordinal;
  public final String name() {
    return name;
  }
  public final int ordinal() {
    return ordinal;
  }
  //重写了toString方法
  public String toString() {
    return name;
  }
  //两个枚举进行比较equals和==等价
  public final boolean equals(Object other) {
    return this == other;
  }
  //不允许克隆枚举实例
  protected final Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException();
  }
  //重写了compareTo,比较的是默认的ordinal值
  public final int compareTo(E o) {
    Enum<?> other = (Enum<?>)o;
    Enum<E> self = this;
    if (self.getClass() != other.getClass() &&
        self.getDeclaringClass() != other.getDeclaringClass())
      throw new ClassCastException();
    return self.ordinal - other.ordinal;
  }

  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<E extends Enum<E>> 抽象类提供了基本的枚举功能和基本方法, extends Enum<E> 限定了泛型参数上界为抽象类 Enum 自身,即限定了只有 Enum 的子类才能作为泛型的参数,Enum 的子类即为通过 enum 关键字定义的枚举类


以上内容是玉山整理的笔记,如有错误还请指出