自从Java允许在switch及case语句中使用字符串以来,许多开发人员都使用了这一特性,不过如果使用整型或者枚举的话会更好。这是JDK7中最受欢迎的特性之一,同样的还有自动资源管理以及多异常捕获。尽管我个人不太喜欢这个特性,因为使用枚举的方式其实更好,但我并不是特别反对使用它。一个原因当然是它很方便,如果程序中已经用到了字符串,这样做的确很顺手,不过我建议在生产环境的代码中使用新特性之前最好了解下它是如何工作的。我第一次听说这个特性的时候,我认为这肯定是通过equals()和hashCode()方法来实现的,我更关心的是Java 7中的字符串的switch是如何实现的。我对这个感兴趣还有一个原因,是我想在面试中问一下这个问题,如果面试中有类似这样的一个问题的话会非常有趣。验证它其实非常简单,你只需用字符串写一段switch的代码,然后反编译一下,看看编译器是如何翻译它们的就可以了。那么还等什么,赶快来看下switch中的字符串是如何工作的吧?
原始代码:
这是一个简单的测试程序,它有一个main方法,里面有一个switch块在操作String变量。程序中用到的字符串参数是运行时传递进来的,你可以从main方法的字符串数组中获取到。有三种模式来启动这个程序,主动模式,被动模式,以及安全模式。对于这些已知的确定值,其实用枚举来实现要更好,但如果你已经决定使用字符串了,你得确保你写的是大写的,不要写成小成或者骆驼式的,这样会出现大小写敏感的问题。你还可以看下
这篇教程 ,了解下如何在Java 7的switch表达式中正确地使用字符串。
/** * Java Program to demonstrate how string in switch functionality is implemented in * Java SE 7 release. */
public class StringInSwitchCase {
public static void main(String[] args) {
String mode = args[0];
switch (mode) {
case "ACTIVE":
System.out.println("Application is running on Active mode");
break;
case "PASSIVE":
System.out.println("Application is running on Passive mode");
break;
case "SAFE":
System.out.println("Application is running on Safe mode");
}
}
}
编译运行这段代码需要安装JDK7才行。随便哪个版本的JDK7都可以。
反编译后的代码:
下面是上述代码使用jdk1.7.0_40编译后再反编译的结果。如果你是Java新手,想知道如何反编译Java类来实现逆向工程,看下
这篇文章。JDK的每个版本都会加入越来越多的语法糖,因此对于各个水平的Java开发人员来说,知道 如何反编译Java类是想当重要的。你写的代码和实现执行的差距会越来越大。了解Java类的文件格式以及字节码指令会对你很有帮助 。Java 8最近发布了一个新的特性,叫做lambda表达式,它通过编译器来实现了内部匿名类,你可以反编译下你的类文件来看下编译器都加了些什么。
/** * Reverse Engineered code to show how String in Switch works in Java. */
import java.io.PrintStream;
public class StringInSwitchCase{
public StringInSwitchCase() { }
public static void main(string args[]) {
String mode = args[0];
String s; switch ((s = mode).hashCode()) {
default: break;
case -74056953:
if (s.equals("PASSIVE")) {
System.out.println("Application is running on Passive mode");
}
break;
case 2537357:
if (s.equals("SAFE")) {
System.out.println("Application is running on Safe mode");
}
break;
case 1925346054:
if (s.equals("ACTIVE")) {
System.out.println("Application is running on Active mode");
}
break;
}
}
}
看到这个代码,你知道原来字符串的switch是通过equals和hashCode()方法来实现的。记住,switch中只能使用整型,比如byte。short,char以及int。还好hashCode()方法返回的是int,而不是long。通过这个很容易记住hashCode返回的是int这个事实,事实上我自己都会经常忘了或者弄混。仔细看下可以发现,进行switch的实际是哈希值,然后通过使用equals方法比较进行安全检查,这个检查是必要的,因为哈希可能会发生碰撞。因此它的性能是不如使用枚举进行switch或者使用纯整数常量,但这也不是很差。因为Java编译器只增加了一个equals方法,如果你比较的是字符串字面量的话会非常快,比如"abc" =="abc"。如果你把hashCode()方法的调用也考虑进来了,那么还会再多一次的调用开销,因为字符串一旦创建了,它就会把哈希值缓存起来,这个可以看下我自己比较喜欢的一篇文章
为什么Java中的字符串是不可变的。因此如果这个siwtch语句是用在一个循环里的,比如逐项处理某个值,或者游戏引擎循环地渲染屏幕,这里hashCode()方法的调用开销其实不会很大。不管怎样,我仍然认为使用字符串的switch来代表几个固定的值不是一个最佳实践,Java里的枚举的存在是有它的原因的,每个Java开发人员都应该使用它。
这就是Java 7如何实现的字符串switch。正如我所料,它使用了hashCode()来进行switch,然后通过equals方法进行验证。这其实只是一个语法糖,而不是什么内建的本地功能。选择权在你,我个人来说不是很喜欢在switch语句中使用字符串,因为它使得代码更脆弱,容易出现大小写敏感的问题,而且编译器又没有做输入校验 。事实上对于性能关键的代码,以前的整型常量和枚举的写法是我的最爱,在这里可读性和代码质量都更重要。事实上,99。99%的情况下,枚举都比使用字符串的switch或者整型要好,这也是它们存在于Java语言中的实际意义 。这个特性就是为了改变这种不良的编码实践而生的,我很难找到什么情况下非要针对一组输入值在switch分支中使用字符串,如果你有一个令人信服的使用字符串switch的原因,请告诉我,我或者会改变我现在的想法。
译注:更深入的话可以了解下Java在字节码层面是如何实现的,可参考
这篇文章。
原创文章转载请注明出处:
http://it.deepinmind.com
英文原文链接
分享到:
相关推荐
Java字符串在编程中扮演着重要角色,它们是不可变的对象,这意味着一旦创建,就不能更改其内容。本资料主要涵盖了字符串的比较、转化以及操作运算符的相关知识点。 1. 字符串的比较: Java中提供了两种主要的字符...
标题为"Java中String类(字符串操作)的10个常见问题和解决方法"的文档主要探讨了Java语言中字符串处理的核心类String的使用细节和最佳实践。以下是根据文档内容总结的知识点: 1. 字符串比较 在Java中,比较字符串...
字符串拼接是编程中常见的操作。在Golang中,我们使用加号(+)来连接两个字符串。以下是一个简单的示例: ```go package main import "fmt" func main() { fmt.Println("左手一只鸡" + "右手一只鸭") } ``` 这里,...
本文将详细介绍十个最常见Java字符串问题,及其解决方案。 1. 字符串比较问题 在Java中,比较字符串有两种常见方法:"==" 和 "equals()"。"==" 用于比较两个字符串是否指向内存中的同一个对象,而 "equals()" 用于...
然而,它也有一些限制,比如无法像C++或Java那样在`case`中使用范围或字符串模式匹配。在更复杂的场景下,可能需要结合`if-elif-else`语句或者使用元类(metaclass)和装饰器(decorator)来实现更复杂的逻辑。 在...
Java中还有一些内置的函数来辅助实现进制转换,比如`Integer.toString(int num, int radix)`可以将十进制数转换成任意进制的字符串表示,而`Integer.parseInt(String s, int radix)`则可以将任意进制的字符串转换成...
字符串处理是Java中的一个重要方面,Java提供了String类来处理字符串数据。字符串的方法包括连接、比较、替换、转换大小写等。数组是用于存储固定大小的同一类型元素的数据结构。Java的数组在声明和初始化后,其大小...
Java 中的正则表达式是指可以使用正则表达式来实现字符串匹配和验证。在 Java 中,我们可以使用正则表达式来实现字符串匹配和验证。 Java 中的 IO 操作是指可以使用 IO 操作来实现输入和输出操作。在 Java 中,...
2. 字符串常量池:在Java SE 7中,字符串常量池被移动到了堆内存中,这使得字符串的共享更加高效,减少了对栈内存的压力。 3. invokedynamic指令:这是Java 7引入的一个新字节码指令,用于动态语言支持,允许在运行...
- switch表达式的值和case标签的值在进行比较时,不会进行任何类型转换,因此,如果case标签是一个字符串,那么switch表达式也必须是一个字符串。 - switch语句不能与`null`进行比较,因为`null`不是一个具体的类型...
这个PDF很可能是为Java初学者或需要深入理解Java字符串操作的开发者准备的。 在Java编程中,语法是基础,而字符串处理则是日常开发中的常见任务。以下是一些关键的Java语法和字符串方法的知识点: 1. **Java语法**...
Java中的字符串是不可变的,规范解释了字符串的创建、操作和比较方法。同时,字符集部分讲述了Unicode支持以及字符编码的处理。 十、反射与注解 反射是Java动态性的重要体现,允许在运行时检查类和对象的信息。注解...
Java中实现多态主要是通过继承、接口和方法重写(Override)来达成。在运行时,会根据对象的实际类型来调用相应的方法实现。 abstractclass和interface的区别: abstractclass表示抽象类,可以包含抽象方法和具体...
自Java 7起,`switch`语句支持字符串类型的表达式。这大大增强了`switch`语句的功能和灵活性,使其能更广泛地应用于实际开发中。 ##### 3. `switch`表达式的新特性 自Java 14起,`switch`表达式被引入,它可以作为一...
- `startsWith()`和`endsWith()`方法的使用,检查字符串是否以特定字符或子串开头或结尾。 - 字符串常量的拼接与比较。 4. **异常处理与输入输出** - `IOException`的抛出与捕获,展示如何安全地处理输入输出...
例如,Java 7中switch语句开始支持字符串(String)和枚举(Enumeration),这是对原有只支持基本类型的一个重大改进。 糖块一:switch支持String与枚举 在Java 7之前,switch仅支持基本数据类型,如int、char等。但...
Java中的字符串(String)是一个不可变的字符序列。Java提供了丰富的String类方法用于执行各种字符串操作,如连接、比较、子串查找等。 Java中的集合框架(Collections Framework)提供了一套性能优化的数据结构,...
字符串(String)则是用于处理文本的类,Java中的字符串是不可变的,即一旦创建,其内容无法更改。 8. Java中的输入输出:Java的输入输出是通过IO流来实现的,它包括字节流(如InputStream和OutputStream)和字符流...
3.2 语句:讲解了Java中的控制语句,如if、switch、while、for等。 第四章:类,对象,和接口 4.1 编程语言的几个发展阶段:回顾了编程语言的发展历程,包括机器语言、过程式语言、面向对象编程等。 4.2 类:深入讲解...