`
wzju64676266
  • 浏览: 13889 次
  • 性别: 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)作为编程语言中一种特殊的类型,为开发者提供了一种简洁、清晰的定义一组命名常量的方式。在C#语言中,枚举是通过`enum`关键字定义的,其本质上是一种结构体,与整型(int)紧密相关联,但提供了更丰富...

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

    在编程世界中,`enum`(枚举)和`switch`语句是C++和许多其他编程语言中的关键构造,用于提高代码可读性和效率。本文将深入探讨这两个概念,并结合VC++(Visual C++)环境下的实际案例,提供一个6页的详细分析。 ...

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

    在Java编程语言中,`enum`(枚举)和`switch`语句是两个非常重要的概念,它们在软件开发中有着广泛的应用。本教程将深入探讨这两个知识点,并通过实例源代码帮助你理解它们的用法。 `enum`是Java中的一个特殊的类...

    Java枚举类型Enum的用法

    Java枚举类型(Enum)是Java SE 5.0引入的一种新的数据类型,它为开发者提供了更为强大且安全的方式来表示一组常量。枚举在Java中不仅是一个类,还是一种特殊的类型,允许我们定义自己的常量集合。接下来,我们将...

    Java enum的用法详解

    在 JDK 1.6 之前,switch 语句只支持 `int`、`char` 和 `enum` 类型。使用 enum,可以让我们的代码可读性更强。例如: ```java enum Signal { GREEN, YELLOW, RED } public class TrafficLight { Signal color = ...

    C++中枚举类型(enum)

    ### C++中的枚举类型(Enum) 在C++编程语言中,枚举(`enum`)是一种用户定义的...总之,枚举类型是C++中非常实用的数据类型之一,它不仅可以提高代码的可读性和可维护性,还能帮助开发者更直观地管理有限的选项集。

    Enum的用法

    ### Enum的深度解析与应用技巧 #### 一、Enum的本质与特性 `Enum`,作为Java语言中的一个关键字,自JDK 5.0引入以来,便赋予了开发者一种全新的数据类型——枚举类型,其设计初衷在于为编程提供更安全、更简洁的...

    Enum汇总大全详细讲解

    switch (this) { case RED: if ("红色".equals(name)) {this.name = name;} break; case GREEN: if ("绿色".equals(name)) {this.name = name;} break; case BLUE: if ("蓝色".equals(name)) {this.name = name;...

    Java Enum使用Demo源码

    switch (this) { case SATURDAY: return MONDAY; case SUNDAY: return MONDAY; default: return values()[ordinal() + 1]; } } } ``` 这里,`nextWorkingDay()`方法根据当前枚举值返回下一个工作日。`...

    对enum简单的封装

    在编程领域,枚举(Enum)是一种非常常见且实用的数据类型,它用于定义一组相关的常量。枚举常被用来表示一组预定义的值,这些值通常代表某种特定的分类或者状态。在Java、C#等面向对象的语言中,枚举(Enum)是语言...

    java中enum枚举的详细用法

    Java中的枚举(enum)类型是在JDK 1.5版本引入的一个强大的特性,它用于定义一组相关的常量。在C/C++等语言中,枚举通常用来表示一组具有固定值的常量集合,但在Java中,枚举不仅限于此,它提供了更多的功能和灵活性...

    在java switch中使用String作为分支条件

    在Java中,`switch`语句最初只能处理`int`、`char`以及`enum`类型的数据。然而,在实际开发过程中,有时需要根据字符串(`String`)来执行不同的逻辑分支。为了解决这一问题,Java 7引入了一个新特性——支持直接在`...

    Objective-C switch 语句

    Objective-C的`switch`语句可以比较的不仅是整型常量,还可以是枚举类型(`enum`)或者字符串(`NSString`)。例如: ```objc typedef enum { ColorRed, ColorGreen, ColorBlue } Color; Color color = Color...

    CLI_1.rar_C++/CLI_CLI switch_The Switch_cli_switch cli

    首先,"switch"语句可以与枚举类型(enum)一起使用,这是.NET框架的一个特性。枚举类型提供了强类型和可读性,使得代码更加结构化。例如: ```cpp enum Color { Red, Green, Blue }; Color myColor = Color::Green...

    枚举类型在switch语句中的用法

    ### 枚举类型在switch语句中的用法 在编程语言中,枚举(Enum)是一种数据类型,它由一组固定的常量组成,通常用于表示有限的预定义值...总之,正确使用枚举类型和`switch`语句是编写高质量、可维护的代码的关键之一。

    TestEnum.zip_DEMO_enum学习

    在`TestEnum`这个示例程序中,可能会演示如何声明、初始化枚举、枚举变量的使用,以及与之相关的各种操作。可能还会涉及枚举成员的遍历,例如通过`foreach`循环。此外,可能还会展示如何处理枚举的Flags特性,这在...

    enum 简单使用例子

    枚举(enum)在编程语言中是一种非常常见且实用的数据类型,它用于定义一组相关的命名常量。在C#中,枚举(enum)是一种强类型的数据结构,它基于整数类型,如int、byte、short等。枚举提供了一种更加清晰、可读性更...

Global site tag (gtag.js) - Google Analytics