switch之enum

 

记得曾经去一家公司面试,那时啥也不懂,面试我的那个人好像呆过IBM,数据结构、编译原理这些都很NB。

 

问答环节

他:java switch中能支持什么类型?

 

我:byte short char int ,jdk1.5出来了enum,同样也支持enum

 

他:为什么能支持byte short char int   而long不行?

 

我:这个可能是设计问题

 

他:其实jvm执行class文件的时候,byte short char int这些都是当int类型来执行的,long不能直接转换成int,编译阶段就通不过了。

 

我:我那个时候不太理解他说的那个意思,只能点点头

 

 

他:好,那接着讨论switch为什么支持enum,刚才也讨论过switch其实都是int类型,也只支持int,那enum不是int类型,是个对象,那为什么支持呢!

 

我:那个时候我就蒙了(心里想着,你这家伙,就胡扯),但我讲不出理由,就直接说不知道

 

 

他:其实在switch中enum也是int类型

 

我:心想----我不知道你说的是对还是错,你怎么说都行

自从那以后,哥去研究虚拟机,java指令

 

 

 

 好,废话不多说了,现在来看一下代码,代码比较简单!

 

 

/*************************************
 *************************************
				源代码
 *************************************
 *************************************/
public static void testSwitchInt() {
	int intElement = 3;
	switch (intElement) {
	case 3:
		System.out.println("3");
		break;
	default:
		System.out.println("int DEFAULT");
		break;
	}
}
//int 类型反编译跟源代码是一样的



/*************************************
 *************************************
		用javap工具看class指令
 *************************************
 *************************************/

//case 的值本来就是int,这没什么好说的
public static void testSwitchInt();
  Code:
   Stack=2, Locals=1, Args_size=0
   0:   iconst_3      //解释:加载int常量3
   1:   istore_0     //解释:保存int类型到局部变量表index为0的位置(其实保存的就是3)
   2:   iload_0      //加载局部变量表index为0的位置的int变量,用于switch里面
   3:   lookupswitch{ //1
                3: 20;
                default: 31 }
   20:  getstatic       #9; //Field java/lang/System.out:Ljava/io/PrintStream;
   23:  ldc     #13; //String 3
   25:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
   28:  goto    39
   31:  getstatic       #9; //Field java/lang/System.out:Ljava/io/PrintStream;
   34:  ldc     #14; //String int DEFAULT
   36:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
   39:  return
 

--------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------




/*************************************
 *************************************
				源代码
 *************************************
 *************************************/

public static void testSwitchChar() {
	int charElement = 'a';   //ascii对应的是97,编译器直接把这个值编译成97,case里面也是这样的
	switch (charElement) {
	case 'a':
		System.out.println("a");
		break;
	default:
		System.out.println("char DEFAULT");
		break;
	}
}

/*************************************
 *************************************
				编译后的代码
 *************************************
 *************************************/
public static void testSwitchChar()
{
	int charElement = 97;   
	switch(charElement)
	{
	case 97: // 'a'
		System.out.println("a");
		break;

	default:
		System.out.println("char DEFAULT");
		break;
	}
}

/*************************************
 *************************************
    	用javap工具看class指令
 *************************************
 *************************************/
//case 的值本来就是char类型,但被编译器处理成int 
public static void testSwitchChar();
  Code:
   Stack=2, Locals=1, Args_size=0
   0:   bipush  97   //解释:加载int常量97,a的ascii码
   2:   istore_0    //接下来和上面都一样的
   3:   iload_0    
   4:   tableswitch{ //97 to 97
                97: 24;
                default: 35 }
   24:  getstatic       #46; //Field java/lang/System.out:Ljava/io/PrintStream;
   27:  ldc     #68; //String a
   29:  invokevirtual   #53; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
   32:  goto    43
   35:  getstatic       #46; //Field java/lang/System.out:Ljava/io/PrintStream;
   38:  ldc     #70; //String char DEFAULT
   40:  invokevirtual   #53; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
   43:  return

byte  short  也是同理,都会编译成int



--------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------
*************************上面的例子都比较好理解,enum大家可能也会有点疑惑*********************************


/*************************************
 *************************************
				源代码
 *************************************
 *************************************/
enum EnumTest {
	WINTER, SUMMER, SPRING, AUTUMN;
}
public static void testSwitchEnum() {
	EnumTest enumElement = EnumTest.AUTUMN;
	switch (enumElement) {
	case AUTUMN:
		System.out.println("AUTUMN");
		break;
	default:
		System.out.println("enum DEFAULT");
		break;
	}
}

/*************************************
 *************************************
			enum类编译后的代码
 *************************************
 *************************************/

 //enum其实也就是个普通的类,继承Enum
public final class EnumTest extends Enum
{

    private EnumTest(String s, int i)
    {
        super(s, i);    
		
		/*调用父类的构造函数
		protected Enum(String name, int ordinal) {
		this.name = name;    //名称
		this.ordinal = ordinal;   元素位置
		}
		*/
    }

    public static EnumTest[] values()
    {
        EnumTest aenumtest[];
        int i;
        EnumTest aenumtest1[];
        System.arraycopy(aenumtest = ENUM$VALUES, 0, aenumtest1 = new EnumTest[i = aenumtest.length], 0, i);
        return aenumtest1;
    }

    public static EnumTest valueOf(String s)
    {
        return (EnumTest)Enum.valueOf(meiju/EnumTest, s);
    }

    public static final EnumTest WINTER;
    public static final EnumTest SUMMER;
    public static final EnumTest SPRING;
    public static final EnumTest AUTUMN;
    private static final EnumTest ENUM$VALUES[];

    static 
    {
		//enum的位置的排好的,想数组一样,enum元素最终都保存在ENUM$VALUES数组
        WINTER = new EnumTest("WINTER", 0);  
        SUMMER = new EnumTest("SUMMER", 1);
        SPRING = new EnumTest("SPRING", 2);
        AUTUMN = new EnumTest("AUTUMN", 3);
        ENUM$VALUES = (new EnumTest[] {
            WINTER, SUMMER, SPRING, AUTUMN
        });
    }
}
/*************************************
 *************************************
	testSwitchEnum方法编译后的代码
 *************************************
 *************************************/

 用到enum元素,所以会在当前类中多生成一个$SWITCH_TABLE$meiju$EnumTest()方法和$SWITCH_TABLE$meiju$EnumTest[]变量,用于switch
 static int[] $SWITCH_TABLE$meiju$EnumTest()
{
	$SWITCH_TABLE$meiju$EnumTest;
	if($SWITCH_TABLE$meiju$EnumTest == null) goto _L2; else goto _L1
_L1:
	return;
_L2:
	JVM INSTR pop ;
	int ai[] = new int[EnumTest.values().length];
	try
	{
		ai[EnumTest.AUTUMN.ordinal()] = 4;
	}
	catch(NoSuchFieldError _ex) { }
	try
	{
		ai[EnumTest.SPRING.ordinal()] = 3;
	}
	catch(NoSuchFieldError _ex) { }
	try
	{
		ai[EnumTest.SUMMER.ordinal()] = 2;
	}
	catch(NoSuchFieldError _ex) { }
	try
	{
		ai[EnumTest.WINTER.ordinal()] = 1;
	}
	catch(NoSuchFieldError _ex) { }
	return $SWITCH_TABLE$meiju$EnumTest = ai;
}

private static int $SWITCH_TABLE$meiju$EnumTest[];//保存的是enum的index



 public static void testSwitchEnum()
{
	EnumTest enumElement = EnumTest.AUTUMN;

	//这个就是上面所用到的变量
	switch($SWITCH_TABLE$meiju$EnumTest()[enumElement.ordinal()])
	{
	case 4: // '\004'     因为enum类的元素其实就是个常量,在编译阶段就能确定值,在源代码的case AUTUMN:   其实也就被他所在的ordinal()给替换掉了,其实就是索引
		System.out.println("AUTUMN");
		break;

	default:
		System.out.println("enum DEFAULT");
		break;
	}
}


/*************************************
 *************************************
    	用javap工具看class指令
 *************************************
 *************************************/
public static void testSwitchEnum();
  Code:
   Stack=2, Locals=1, Args_size=0
   0:   getstatic       #6; //Field meiju/EnumTest.AUTUMN:Lmeiju/EnumTest;
   3:   astore_0
   4:   getstatic       #7; //Field meiju/SwitchEnum$1.$SwitchMap$meiju$EnumTest
:[I
   7:   aload_0
   8:   invokevirtual   #8; //Method meiju/EnumTest.ordinal:()I
   11:  iaload
   12:  lookupswitch{ //1
                1: 32;
                default: 43 }
   32:  getstatic       #9; //Field java/lang/System.out:Ljava/io/PrintStream;
   35:  ldc     #10; //String AUTUMN
   37:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
   40:  goto    51
   43:  getstatic       #9; //Field java/lang/System.out:Ljava/io/PrintStream;
   46:  ldc     #12; //String enum DEFAULT
   48:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
   51:  return

 事实证明当时他不是忽悠我,确实是这样的:)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值