java枚举报错_关于java枚举类型的疑问

enum是jdk5引入的语法糖,定义一个enum类实际上也是定义一个class,只是通过enum定义这个特殊class的时候,编译器会帮你做些事情:

所有的枚举类会默认继承Enum类

所有的枚举类是final的,不可扩展子类

所有定义的枚举常量,会生成定义的枚举类中生成public static final常量

所以,枚举类和普通类的用法没有太大的区别,譬如:

case1:

public enum TrafficLight {

RED("红灯"),

GREEN("绿灯"),

YELLOW("黄灯"),

;

private final String desc;

TrafficLight (String desc) { this.desc = desc; }

public String getDesc() { return desc; }

}

case2:

public enum TrafficLight {

RED("红灯") {

public TrafficLight next() { return YELLOW; }

},

GREEN("绿灯") {

public TrafficLight next() { return RED; }

},

YELLOW("黄灯") {

public TrafficLight next() { return GREEN; }

},

;

private final String desc;

TrafficLight (String desc) { this.desc = desc; }

public String getDesc() { return desc; }

public abstract TrafficLight next();

}

根据上面的描述:

第一个问题:Direction d = Direction.EAST;的答案就很显然了,赋值枚举变量的时候,当然要带前缀了,因为这些枚举常量是指定枚举类中的常量,必须加上类限定前缀。

java的switch语法,是通过jvm的tableswitch和lookupswitch两个指令实现。简单说一下实现原理:java编译器为switch语句编译成一个局部变量数组,每个case对应一个数组的索引,指令的执行是通过不同的数组索引找到不同的入口指令。所以原则上switch...case只能处理int型的变量。

enum能用在switch语句中,也是一个语法糖,我们知道所有枚举类的父类Enum中有一个private final int ordinal;,java编译器检测到switch语句中变量是一个枚举类,则会利用之前枚举类的ordinal属性,编译一个局部变量数组,后续在进行case分支比较的时候,就是简单通过tableswitch或lookupswitch指令来进行跳转,需要注意的一点:这个局部变量数组的构建过程是在编译器在编译阶段完成的。

给一个简单的实例:

package com.lee.test;

public class Traffic {

public static void main(String[] args) {

Light light = Light.RED;

switch(light) {

case RED:

System.out.println("红灯");

break;

case GREEN:

System.out.println("绿灯");

break;

case YELLOW:

System.out.println("黄灯");

break;

}

}

enum Light { RED, GREEN, YELLOW }

}

javap -c 反编译后的字节码:

public class com.lee.test.Traffic extends java.lang.Object{

public com.lee.test.Traffic();

Code:

0: aload_0

1: invokespecial #10; //Method java/lang/Object."":()V

4: return

public static void main(java.lang.String[]);

Code:

0: getstatic #18; //Field com/lee/test/Traffic$Light.RED:Lcom/lee/test/Traffic$Light;

3: astore_1

4: invokestatic #24; //Method $SWITCH_TABLE$com$lee$test$Traffic$Light:()[I

7: aload_1

8: invokevirtual #27; //Method com/lee/test/Traffic$Light.ordinal:()I

11: iaload

12: tableswitch{ //1 to 3

1: 40;

2: 51;

3: 62;

default: 70 }

40: getstatic #31; //Field java/lang/System.out:Ljava/io/PrintStream;

43: ldc #37; //String 红灯

45: invokevirtual #39; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

48: goto 70

51: getstatic #31; //Field java/lang/System.out:Ljava/io/PrintStream;

54: ldc #45; //String 绿灯

56: invokevirtual #39; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

59: goto 70

62: getstatic #31; //Field java/lang/System.out:Ljava/io/PrintStream;

65: ldc #47; //String 黄灯

67: invokevirtual #39; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

70: return

static int[] $SWITCH_TABLE$com$lee$test$Traffic$Light();

Code:

0: getstatic #53; //Field $SWITCH_TABLE$com$lee$test$Traffic$Light:[I

3: dup

4: ifnull 8

7: areturn

8: pop

9: invokestatic #55; //Method com/lee/test/Traffic$Light.values:()[Lcom/lee/test/Traffic$Light;

12: arraylength

13: newarray int

15: astore_0

16: aload_0

17: getstatic #59; //Field com/lee/test/Traffic$Light.GREEN:Lcom/lee/test/Traffic$Light;

20: invokevirtual #27; //Method com/lee/test/Traffic$Light.ordinal:()I

23: iconst_2

24: iastore

25: goto 29

28: pop

29: aload_0

30: getstatic #18; //Field com/lee/test/Traffic$Light.RED:Lcom/lee/test/Traffic$Light;

33: invokevirtual #27; //Method com/lee/test/Traffic$Light.ordinal:()I

36: iconst_1

37: iastore

38: goto 42

41: pop

42: aload_0

43: getstatic #62; //Field com/lee/test/Traffic$Light.YELLOW:Lcom/lee/test/Traffic$Light;

46: invokevirtual #27; //Method com/lee/test/Traffic$Light.ordinal:()I

49: iconst_3

50: iastore

51: goto 55

54: pop

55: aload_0

56: dup

57: putstatic #53; //Field $SWITCH_TABLE$com$lee$test$Traffic$Light:[I

60: areturn

Exception table:

from to target type

16 25 28 Class java/lang/NoSuchFieldError

29 38 41 Class java/lang/NoSuchFieldError

42 51 54 Class java/lang/NoSuchFieldError

}

}

根据上述的描述:

枚举变量的定义、赋值是运行时jvm强制要求类型必须一致,所以必须加上类限定前缀;而在switch...case中使用枚举变量,则只是java提供的语法糖,这个特色并不是在运行时通过JVM来保证的,而只是java编译器在编译阶段完成的,在编译过程中的一旦判断switch语句中的变量是enum类型,即只需要以其ordinal属性为索引,通过tableswitch查找局部变量数组(这在反编译后的7~12行字节码可以体现出)。在此时case语句不需要类限定前缀,完全是java编译器的限制(编译器是不需要枚举类的前缀,只需要枚举类编译的static

int[] $SWITCH_TABLE)。

PS: JDK7中switch...case语法新增支持string字面量是差不多同样的道理,java编译器根据string常量的hashcode值,在编译阶段构建局部常量数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值