枚举类型详解


  简介:关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用。这是一种非常有用的功能。

1. enum基本特性

  创建 enum 时,编译器会为你生成一个相关的类,这个类继承自java.lang.Enum。能够使用它的方法

enum Shrubbery {
    GROUND, CRAWLING, HANGING
}

public class EnumClass {

    public static void main(String[] args) {
        for (Shrubbery shrubbery : Shrubbery.values()) {
            System.out.println(shrubbery + " ordinal:" + shrubbery.ordinal());
            System.out.println(shrubbery.compareTo(Shrubbery.CRAWLING) + " ");
            System.out.println(shrubbery.equals(Shrubbery.CRAWLING) + " ");
            System.out.println(shrubbery == Shrubbery.CRAWLING);
            System.out.println(shrubbery.getDeclaringClass());
            System.out.println(shrubbery.name());
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~");
        }
    }

}

  输出结果:

GROUND ordinal:0
-1 
false 
false
class com.zhihong.Test19.Shrubbery
GROUND
~~~~~~~~~~~~~~~~~~~~~~~~~~
CRAWLING ordinal:1
0 
true 
true
class com.zhihong.Test19.Shrubbery
CRAWLING
~~~~~~~~~~~~~~~~~~~~~~~~~~
HANGING ordinal:2
1 
false 
false
class com.zhihong.Test19.Shrubbery
HANGING
~~~~~~~~~~~~~~~~~~~~~~~~~~
  • ordinal() 方法返回一个int值(每个 enum 实例声明时的次序,从0开始)。可以用 == 来比较 enum 实例,也可以使用 java.lang.Enum 的 equals(方法。
  • 如果在 enum 实例上调用 getDeclaringClass() 方法,我们就可以知道起所属 enum 类。
  • 我们可以使用 enum 实例自带 valueof() 或 java.lang.Enum 定义的 static 的 valueof() 方法,根据给定的名称返回相应的 enum 实例。
Shrubbery crawling = Shrubbery.valueOf("CRAWLING");
Shrubbery crawling1 = Enum.valueOf(Shrubbery.class, "CRAWLING");

2. 静态导入enum

package com.zhihong.Test19;

public enum Spiciness {
    NOT, MILD, MEDIUM, HOT, FLAMING
}

package com.zhihong.Test;

import static com.zhihong.Test19.Spiciness.*;

public class EnumTest {
    public static void main(String[] args) {
        System.out.println(MEDIUM);
        System.out.println(HOT);
        System.out.println(FLAMING);
    }
}

  静态导入 enum,无需要用 enum 类型修饰其实例,可以直接使用 enum 实例

3. 向 enum 中添加新方法

  除了不能继承自一个 enum 之外,我们基本上可以将 enum 看作一个常规的类。也就是说,我们可以向 enum 种添加方法。enum 甚至可以有 main() 方法。

public enum Fruits {
    APPLE("苹果"),
    BANANA("香蕉"),
    PEAR("梨");

    private String description;

    private Fruits(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public static void main(String[] args) {
        for (Fruits fruits : Fruits.values()) {
            System.out.println(fruits.name() + ":" + fruits.getDescription());
        }
    }
}
result:
APPLE:苹果
BANANA:香蕉
PEAR:梨

4. values() 的神秘之处

  前面提到,编译器为你创建 enum 类都继承自 Enum 类。然而,如果你研究一下 Enum 类就会发现,它并没有values() 方法。我们可以利用 javap 机制来查看其中的究竟。

public enum Spiciness {
    MEDIUM, HOT, FLAMING
}

Compiled from "Spiciness.java"
public final class com.zhihong.Test19.Spiciness extends java.lang.Enum<com.zhihong.Test19.Spiciness> {
  public static final com.zhihong.Test19.Spiciness NOT;
    descriptor: Lcom/zhihong/Test19/Spiciness;

  public static final com.zhihong.Test19.Spiciness MILD;
    descriptor: Lcom/zhihong/Test19/Spiciness;

  public static final com.zhihong.Test19.Spiciness MEDIUM;
    descriptor: Lcom/zhihong/Test19/Spiciness;

  public static final com.zhihong.Test19.Spiciness HOT;
    descriptor: Lcom/zhihong/Test19/Spiciness;

  public static final com.zhihong.Test19.Spiciness FLAMING;
    descriptor: Lcom/zhihong/Test19/Spiciness;

  public static com.zhihong.Test19.Spiciness[] values();
    descriptor: ()[Lcom/zhihong/Test19/Spiciness;
    Code:
       0: getstatic     #1                  // Field $VALUES:[Lcom/zhihong/Test19/Spiciness;
       3: invokevirtual #2                  // Method "[Lcom/zhihong/Test19/Spiciness;".clone:()Ljava/lang/Object;
       6: checkcast     #3                  // class "[Lcom/zhihong/Test19/Spiciness;"
       9: areturn
    LineNumberTable:
      line 3: 0

  public static com.zhihong.Test19.Spiciness valueOf(java.lang.String);
    descriptor: (Ljava/lang/String;)Lcom/zhihong/Test19/Spiciness;
    Code:
       0: ldc           #4                  // class com/zhihong/Test19/Spiciness
       2: aload_0
       3: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
       6: checkcast     #4                  // class com/zhihong/Test19/Spiciness
       9: areturn
    LineNumberTable:
      line 3: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      10     0  name   Ljava/lang/String;

  static {};
    descriptor: ()V
    Code:
       0: new           #4                  // class com/zhihong/Test19/Spiciness
       3: dup
       4: ldc           #7                  // String NOT
       6: iconst_0
       7: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      10: putstatic     #9                  // Field NOT:Lcom/zhihong/Test19/Spiciness;
      13: new           #4                  // class com/zhihong/Test19/Spiciness
      16: dup
      17: ldc           #10                 // String MILD
      19: iconst_1
      20: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      23: putstatic     #11                 // Field MILD:Lcom/zhihong/Test19/Spiciness;
      26: new           #4                  // class com/zhihong/Test19/Spiciness
      29: dup
      30: ldc           #12                 // String MEDIUM
      32: iconst_2
      33: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      36: putstatic     #13                 // Field MEDIUM:Lcom/zhihong/Test19/Spiciness;
      39: new           #4                  // class com/zhihong/Test19/Spiciness
      42: dup
      43: ldc           #14                 // String HOT
      45: iconst_3
      46: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      49: putstatic     #15                 // Field HOT:Lcom/zhihong/Test19/Spiciness;
      52: new           #4                  // class com/zhihong/Test19/Spiciness
      55: dup
      56: ldc           #16                 // String FLAMING
      58: iconst_4
      59: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
      62: putstatic     #17                 // Field FLAMING:Lcom/zhihong/Test19/Spiciness;
      65: iconst_5
      66: anewarray     #4                  // class com/zhihong/Test19/Spiciness
      69: dup
      70: iconst_0
      71: getstatic     #9                  // Field NOT:Lcom/zhihong/Test19/Spiciness;
      74: aastore
      75: dup
      76: iconst_1
      77: getstatic     #11                 // Field MILD:Lcom/zhihong/Test19/Spiciness;
      80: aastore
      81: dup
      82: iconst_2
      83: getstatic     #13                 // Field MEDIUM:Lcom/zhihong/Test19/Spiciness;
      86: aastore
      87: dup
      88: iconst_3
      89: getstatic     #15                 // Field HOT:Lcom/zhihong/Test19/Spiciness;
      92: aastore
      93: dup
      94: iconst_4
      95: getstatic     #17                 // Field FLAMING:Lcom/zhihong/Test19/Spiciness;
      98: aastore
      99: putstatic     #1                  // Field $VALUES:[Lcom/zhihong/Test19/Spiciness;
     102: return
    LineNumberTable:
      line 4: 0
      line 3: 65
}

  答案是,values() 是由编译器添加的 static 方法。可以看出编译器还为其添加了 valueOf() 方法。

5. 常量相关的方法

  Javaenum 有一个非常有趣的特性,即它允许程序员为 enum 实例编写方法,从而为每个 enum 实例赋予各自不同的行为。

public enum ConstantSpecificMethod {

    DATE_TIME {
        public String getInfo() {
            return "date time";
        }
    },

    CLASSPATH {
        public String getInfo() {
            return "classpath";
        }
    };

    public abstract String getInfo();

    public static void main(String[] args) throws IOException {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        for (ConstantSpecificMethod value : values()) {
            System.out.println(value.getInfo());
            System.out.println(value.getClass().getName());
        }
    }
}
result:    
date time
com.zhihong.Test19.ConstantSpecificMethod$1
classpath
com.zhihong.Test19.ConstantSpecificMethod$2

可以看出每个 enum 实例的 class 都不一样了,各自重写了 abstract String getInfo()方法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值