`
wzju64676266
  • 浏览: 13645 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

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

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

3
3
分享到:
评论
3 楼 chenchao051 2011-02-28  
哈哈,楼主太有才了。
2 楼 wzju64676266 2011-01-15  
lfsfxy9 写道
事实胜于雄辩,学习了。

javap 命令。


共同学习,javap绝对是个好东西,如果了解过字节码一般都看得懂
1 楼 lfsfxy9 2011-01-15  
事实胜于雄辩,学习了。

javap 命令。

相关推荐

    枚举enum和switch 的使用

    自己整理枚举enum和switch 的使用代码

    7enum和switch语句联合案例分析VC共6页.pdf

    7enum和switch语句联合案例分析VC共6页.pdf.zip

    Java 实例 - enum 和 switch 语句使用源代码-详细教程.zip

    Java 实例 - enum 和 switch 语句使用源代码-详细教程.zip

    switch 语句switch 语句

    它也适用于 enumerated types (枚举类型)(在 Enum Types 中讨论),String 类以及一些包装某些原始类型的特殊类:Character,Byte,Short 和 Integer(在 Numbers and Strings 中讨论)。 以下代码示例 SwitchDemo ...

    PHP中Enum(枚举)用法实例详解

    本文实例讲述了PHP中Enum(枚举)用法。分享给大家供大家参考,具体如下: PHP其实有Enum类库的,需要安装perl扩展,所以不是php的标准扩展,因此代码的实现需要运行的php环境支持。 (1)扩展类库SplEnum类。该类的...

    枚举(switch、覆盖枚举、实现接口等)

    JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。 enum Signal { GREEN, YELLOW, RED } public class TrafficLight { Signal color = Signal.RED; public void ...

    详解Swift中enum枚举类型的用法

    Swift中通过enum关键字可以直接创建出枚举对象,而且可以使用switch和case语句来进行流程控制,十分强大和灵活,这里我们就来详解Swift中enum枚举类型的用法

    C语言 由ANSI标准定义的32个关键字

    auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if while static

    C++基本概念 (面试、复习)

    long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if static while asm _cs _ds _es _ss cdecl far huge ...

    Amplify Shader Editor 1.4.3

    * Fixed ‘Static Switch’ node registering duplicates in the material properties group * Improvements: * Cull, Stencil, Color Mask and Depth options can now reference properties instead of standard...

    C#编写的简单词法分析

    auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do while static f ...

    C#如何给枚举类型增加一个描述特性详解

    如果我们在页面上直接输出我们希望匹配的汉语意思或则其他满足我们需求的语句就更好了,当然,通常小伙伴们都会再页面上if(enum==1) “我是一个枚举”或者switch(enum)这种方式解决。 枚举的优点: 枚举可以使...

    C_gjz.rar_float

    break:跳出当前循环 else :条件语句否定分支(与 if 连用) switch :用于开关语句 case:开关语句分支 enum :声明枚举类型 register:声明积存器变量 typedef:用以给数据类型取别名 char :声明字符型变量或函数...

    fsp-usb:自定义Nintendo Switch服务以安装和访问USB驱动器

    自定义Nintendo Switch服务以安装和访问USB驱动器 信息 这个sysmodule将成为Atmosphere的一部分,但是由于缺乏动力,我停止了几个月的研究。 这是尝试移植旧代码并修复可能存在的错误的尝试,并且仍在进行中。 不...

    C++程序设计课程设计银行账户管理系统源程序.doc

    enum Status {UNHOOKED,HOOKED}; enum MenuType {MAINMENU, ADM_SUBMENU, USER_SUBMENU}; enum FuncType {NONE, ADM_MOD, USER_MOD, OPEN_ACCOUNT, REPORT_LOSS, UNHOOKING, CLOSE_ACCOUNT, SAVING, DRAWING, ...

    哈希表查找

    "double", "else", "enum", "extern", "float", "for", "goto", "if", "int", "long", "register", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", ...

    ngrx-enums:一个小型库,为将ts-enum用于@ngrx操作和reducer提供了基础

    是用于管理Angular应用程序状态的功能非常强大的实用程序,但一些开发人员批评该包含过多的样板文件(尤其是在动作类中),并且在reducers中具有较大的switch语句。 是一个分支,该使用封装动作和简化器,从而减少了...

    C++大学教程,一本适合初学者的入门教材(part2)

    3.9 案例:机会游戏与enum简介 3.10 存储类 3.11 作用域规则 3.12 递归 3.13 使用递归举例:Fibonacci数列 3.14 递归与迭代 3.15 带空参数表的函数 3.16 内联函数 3.17 引用与引用参数 3.18 默认参数 ...

    Java开发手册-华山版-1.5.0.pdf

    比如,switch 的 NPE 问题、浮点数的比较、无泛型限制、锁的使用方式、判断表达式、日期格式等。 3)修改描述 112 处。比如,IFNULL 的判断、集合的 toArray、日志处理等。 4)完善若干处示例。比如,命名示例、卫...

Global site tag (gtag.js) - Google Analytics