`
freish
  • 浏览: 83868 次
  • 性别: Icon_minigender_1
  • 来自: 摄影帝国
社区版块
存档分类
最新评论

jdk1.7 String switch的实现

 
阅读更多

 

对于int的switch,jvm是用tableswitch和lookupswitch来实现的,jdk1.7 switch增加了对string的支持,那么底层是如何实现的呢?是否增加了新的指令或是否给某些指令增加了新的含义?

 

 

看这样一个程序:

 

public class Test {   
	public static void main(String[] args) {  
		String name = "b";
		int value = 0;
		switch(name) {
			case "a":
				value = 1;
				break;
			case "b":
				value = 2;
				break;
			case "c":
				value = 3;
				break;
			case "d":
				value = 4;
				break;
			case "e":
				value = 5;
				break;
			default:
				value = 6;
		}
		System.out.println(value);
	}  
}

 

javap -c Test得出的结果为:

 

 

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String b
       2: astore_1					//将"b"赋值给name
       3: iconst_0					//将0入栈
       4: istore_2					//将0赋值给value
       5: aload_1					//将name(即"b")入栈
       6: astore_3					//将name(即"b")赋值给一个编译器生成的变量,记为tmpName(tmpName此时也是"b")
       7: iconst_m1					//将-1入栈
       8: istore        4			//将-1赋值给一个编译器生成的变量,记为m1
      10: aload_3					//将tmpName(即"b")入栈
      11: invokevirtual #3                  // Method java/lang/String.hashCode:()I		调用tmpName的hashCode方法("b".hashCode(),得结果98)
      14: tableswitch   { // 97 to 101		//根据hashCode的值到不同的分支
                    97: 48
                    98: 63					//这里走到这个分支,跳转到63
                    99: 78
                   100: 93
                   101: 108
               default: 120
          }
      48: aload_3
      49: ldc           #4                  // String a
      51: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      54: ifeq          120
      57: iconst_0
      58: istore        4
      60: goto          120
      63: aload_3							//从14跳转到了这里,将tmpName(即"b")入栈
      64: ldc           #2                  // String b		将"b"入栈
      66: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z	
											//比较tmpName和"b",如果相等,将1入栈,不等将0入栈.这里是相等的,入栈的为1
      69: ifeq          120					//从栈顶取出比较结果,如果等于0,就跳到120,如果不等于0就继续下面的指令,这里显然不等于0
      72: iconst_1							//将1入栈
      73: istore        4					//将1存储到m1中
      75: goto          120					//跳到120
      78: aload_3
      79: ldc           #6                  // String c
      81: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      84: ifeq          120
      87: iconst_2
      88: istore        4
      90: goto          120
      93: aload_3
      94: ldc           #7                  // String d
      96: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      99: ifeq          120
     102: iconst_3
     103: istore        4
     105: goto          120
     108: aload_3
     109: ldc           #8                  // String e
     111: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     114: ifeq          120
     117: iconst_4
     118: istore        4
     120: iload         4					//将m1(即73行存进去的1)的值入栈
     122: tableswitch   { // 0 to 4			
                     0: 156
                     1: 161					//这里走1这个分支,跳到161
                     2: 166
                     3: 171
                     4: 176
               default: 181
          }
     156: iconst_1
     157: istore_2
     158: goto          184
     161: iconst_2					//将2入栈
     162: istore_2					//将2存储到value
     163: goto          184			//跳转到184进行打印输出
     166: iconst_3
     167: istore_2
     168: goto          184
     171: iconst_4
     172: istore_2
     173: goto          184
     176: iconst_5
     177: istore_2
     178: goto          184
     181: bipush        6
     183: istore_2
     184: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
     187: iload_2
     188: invokevirtual #10                 // Method java/io/PrintStream.println:(I)V
     191: return
}
 

 

在这一堆指令中我们发现,jdk1.7并没有新指令来处理string switch,还是继续用lookupswitch和tableswitch两个指令来处理的,也没有扩展这两个指令,它们还是只能处理int。

 

 

在11行,我们看到调用了需要switch的string的hashCode方法,并对该hashCode进行switch,并跳转到相应的处理指令。跳到新的指令处我们发现这里(63行)将待switch的变量(name)与case中的值("b")equals了一下。这样做是为了避免不同的string有相同的hashCode,确定equals返回true后,编译器生成了一个处理value的switch,源码里有多少个case编译器生成的tableswitch就有多少个分支,最终会找到相应的处理分支完成string switch的处理。

 

 

接下来,看一个不同string hashCode相等的版本:

 

buzzards与righto的hashCode相等

hierarch与crinolines的hashCode相等

 

这里选择buzzards和righto

 

 

public class Test {   
	public static void main(String[] args) {  
		String name = "buzzards";
		int value = 0;
		switch(name) {
			case "buzzards":
				value = 1;
				break;
			case "righto":
				value = 2;
				break;
			default:
				value = 6;
		}
		System.out.println(value);
	}  
}
 

 

字节码:

 

 public static void main(java.lang.String[]);
   Code:
      0: ldc           #2                  // String buzzards
      2: astore_1
      3: iconst_0
      4: istore_2
      5: aload_1
      6: astore_3
      7: iconst_m1
      8: istore        4
     10: aload_3
     11: invokevirtual #3                  // Method java/lang/String.hashCode:()I
     14: lookupswitch  { // 1
           -931102253: 32
              default: 59
         }
     32: aload_3
     33: ldc           #4                  // String righto
     35: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)
     38: ifeq          47
     41: iconst_1
     42: istore        4
     44: goto          59
     47: aload_3
     48: ldc           #2                  // String buzzards
     50: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)
     53: ifeq          59
     56: iconst_0
     57: istore        4
     59: iload         4
     61: lookupswitch  { // 2
                    0: 88
                    1: 93
              default: 98
         }
     88: iconst_1
     89: istore_2
     90: goto          101
     93: iconst_2
     94: istore_2
     95: goto          101
     98: bipush        6
    100: istore_2
    101: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
    104: iload_2
    105: invokevirtual #7                  // Method java/io/PrintStream.println:(I)V
    108: return
 

 

 

这里我们看到两个字符串都跳到32行,首先跟"righto"比较,如果不相等则跳到47行比较buzzards。

 

 

13
8
分享到:
评论
3 楼 wkl17 2014-10-26  
字节码 是如何查看的?用记事本打开都是乱码..
2 楼 NeverGiveUpToChange 2012-04-10  
hao hao hao hao hao
1 楼 wupuyuan 2011-08-31  
多谢LZ来分享,我也仔细分析了下,觉得switch String 不如传统的if else来的效率高。当然在if时要判断更准确一些。欢迎去我空间看看

相关推荐

    jdk1.7版本免安装

    2. **开关语句(Switch on String)**:在JDK 1.7之前,switch语句仅支持枚举和整型,但在这个版本中,字符串也被添加到支持的类型中。 3. **多catch块**:允许在一个catch子句中捕获多种异常类型,减少了冗余代码...

    JDK1.7免安装版

    - **字符串inswitch(String in Switch)**: 在`switch`语句中可以直接使用字符串作为条件。 - **二进制字面量与下划线分隔符(Binary Literals & Underscores in Numeric Literals)**: 支持二进制字面量(如`0b...

    jdk1.7 jdk1.7 jdk1.7

    在给定的标题“jdk1.7 jdk1.7 jdk1.7”中,反复提及的“1.7”指的是Java的第七个主要版本,也被称为Java 7。这个版本在2011年发布,为开发者带来了许多新特性和改进,旨在提高开发效率和程序性能。 **一、JDK 1.7的...

    jdk1.7-linux

    - **Strings in Switch**:在switch语句中可以直接使用String对象,增强了可读性。 **2. Linux环境下的JDK安装与配置:** - 下载适用于Linux的JDK 1.7版本,例如提供的文件名`jdk1.7.0_55`。 - 解压缩下载的tar.gz...

    jdk1.7 windows 64位

    - **类型推断(Type Inference)**:通过`<>`操作符实现,简化泛型的使用,如`List<String> list = new ArrayList();` - **多路分支(Switch on Strings)**:允许在switch语句中使用字符串,方便处理枚举类型的比较...

    jdk 1.7 绿色版

    再者,新版本改进了字符串操作,比如添加了`switch`语句对`String`的支持,使得开发者可以根据字符串值进行分支判断。此外,`String`类还增加了`split()`方法的正则表达式优化,提高了处理复杂分隔符的速度。 JDK ...

    jdk1.7 官方正式版64位下载

    JDK1.7新特性介绍 1. 对Java集合(Collections)的增强支持 2. 在Switch中可用String 在JDK7 的正式版本中,你可以在switch的表达式中用String类型 3. 数值可加下划线 下划线字符(_)能够出现在数字字面量的数字...

    jdk1.7 免安装版本

    6. **开关表达式(Switch on String)**: `switch`语句可以接受`String`类型的参数,增强了对枚举类型的支持。 7. **改进的for-each循环**: 可以遍历数组和集合的子范围,如`for (int i : array.subArray(start, ...

    JDK1.7.zip

    **JDK 1.7,也称为Java Development Kit 7,...JDK 1.7压缩包中的文件“JDK1.7”可能包含了完整的JDK安装包,用于在开发环境中安装和使用Java 1.7版本。安装后,开发者可以利用这些新特性编写更加高效、可维护的代码。

    JDK1.7 绿色版本免安装,能用希望给个评价,让大家多多支持

    6. **改进的字符串操作** - 包括`switch`语句对字符串的支持,以及`String`类中新增的一些便捷方法,如`substring()`、`trim()`等。 7. **动态类型语言支持** - 通过JSR 292,Java 7引入了对动态语言的支持,允许在...

    JDK1.7 64位 windows安装版

    JDK1.7,也被称为Java 7,是Oracle公司发布的版本之一,针对64位Windows操作系统进行了优化,使得在Windows环境下开发和运行Java应用更加高效。 在64位Windows系统上安装JDK1.7,首先需要下载对应平台的安装文件,...

    JDK1.7(JavaSE1.7/JDK7)

    JDK1.7,也称为Java SE 1.7或JDK7,是Java开发工具包的一个重要版本,对于Java开发者来说是必备的环境。它在Java发展历程中扮演了关键角色,引入了许多新特性,提升了开发效率并优化了性能。在此,我们将深入探讨JDK...

    jdk1.7免安装版本

    - **Strings in Switch**:在switch语句中可以直接使用String对象。 - **try-with-resources**:自动关闭资源的语法结构,简化了资源管理。 - **新集合接口方法**:如`Map.forEach()`,`List.retainAll()`等,...

    javajdk1.7环境

    Java JDK 1.7,全称为Java Development Kit version 7,是Oracle公司推出的Java编程语言的开发工具包,对于任何想要编写、编译、调试和运行Java程序的开发者来说,都是必不可少的基础。JDK 1.7,也被称为Java SE...

    jdk 1.7 32位 解压版本

    4. **字符串改进**:如`String`类增加了`isBlank()`方法,以及对`switch`语句的支持。 5. **文件系统API**:引入了`java.nio.file`包,提供了更强大和灵活的文件操作接口。 6. **类型注解**:增强了注解的使用范围...

    jdk1.7 windows 64 免安装

    JDK 1.7,也称为Java 7,是Oracle公司发布的一个重要版本,带来了许多新特性、改进和优化。在Windows 64位操作系统上使用JDK 1.7的免安装版本,可以简化安装过程,节省磁盘空间,并方便进行版本切换。 首先,下载...

    JDK1.7源码包

    在JDK1.7中,类型推断使得创建泛型实例变得更加简洁,如`List<String> list = new ArrayList();`,编译器会自动推断出中的类型。 #### 1.2 静态导入(Static Import) 静态导入允许开发者直接使用类的静态成员,而...

    JDK1.7(含配置文档).zip

    7. **动态语言支持**:JDK1.7通过JSR 292(Invokedynamic)提供了对动态语言的更好支持,为实现如Groovy和JRuby等脚本语言的JVM上的高效运行奠定了基础。 **二、JDK1.7的安装过程** 1. **下载**:首先,你需要从...

    jdk1.7 64位 绿色版 官方

    1. **解压**: 首先,将`jdk1.7_64`压缩包解压到任意目录,例如`C:\Program Files\Java\jdk1.7_64`。 2. **设置JAVA_HOME**: 在系统环境变量中新建一个名为`JAVA_HOME`的变量,将其值设置为JDK的安装路径(上述示例中...

    jdk1.7 官方正式版64位——亲测可用.zip

    在这个特定的压缩包"jdk1.7 官方正式版64位——亲测可用.zip"中,我们拥有的是Oracle公司发布的JDK 1.7的64位版本,适用于64位操作系统的计算机。 JDK 1.7,也被称为Java SE 7(Java Standard Edition 7),在2011...

Global site tag (gtag.js) - Google Analytics