Sni*_*las 5 java class switch-statement java-7 java-8
在我看来,这样的switch语句会很有意义,但它会产生编译错误:
public void m(Class c) {
switch (c) {
case SubClassOfC1.class : //do stuff; break;
case SubClassOfC2.class : //do stuff; break;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,不支持打开类.是什么原因?
我不是试图解决方法instanceof,它实际上是在类级别,我有一些操作要执行,没有实例.
编译错误在SubClassOfC1和SubClassOfC2附近: constant expression required.
dur*_*597 10
这是因为我们只能打开常量表达式(§15.28)或枚举常量(§8.9.1).
Expression的类型必须是char,byte,short,int,Character,Byte,Short,Integer,String或枚举类型(第8.9节),否则会发生编译时错误.
想象一下为什么会出现这种情况,请考虑Java编译器尝试编译switch语句时发生的优化.
long与float和double不支持,但是String是).请注意,语句String中支持仅在Java 7中添加.这是因为编译器采用的是背后的场景转换到,因为在这篇文章中详细介绍switchswitch Stringswitch int.快速摘要:
这段代码:
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");
}
}
}
Run Code Online (Sandbox Code Playgroud)
成为这个代码:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我们无法Class以相同的方式可靠地将对象转换为int.类不会覆盖hashCode,它使用System.identityHashCode.
另请注意Class,如果已加载了不同的类,则相同的类并不总是相同的ClassLoader.
交换机使用byte,short,char和int原始数据类型.它还适用于枚举类型(在枚举类型中讨论),String类,以及一些包含某些基本类型的特殊类:Character,Byte,Short和Integer.
从本质上讲,它只能用于那些类型,而不是其他任何类型.Class不是其中之一.
正如您在评论中所说的那样,限制的原因是切换表被索引int.所有上述类型都可以轻松转换为int(包括String通过散列),而Class不是.
有趣的是,到目前为止所有的答案基本上都是"因为规范是这样说的",这是正确的,但并不令人满意.在Java 7之前,String不允许使用s,这通常被视为刻在石头上.
但技术障碍不应该推动语言设计.如果没有办法将它编译成有效的代码,它仍然可以编译为相当于if … else …子句,并且仍然在源代码简洁方面获胜.在String价值观的情况下,有一种有效的方法.只需切换不变的哈希码并对equals匹配候选项执行检查.事实上,规范并没有强制要求使用哈希码,它可以是任何不变的int属性,例如长度或第一个字符,但它的值应该是不同的String.
同样,switch过度Class对象也是可能的.它的哈希码不保证是相同的,但每个类都有一个带有常量哈希码的常量名.例如以下作品:
public class ClassSwitch {
static final class Foo {}
static final class Bar {}
static final class Baz {}
public static void main(String... arg) {
Class<?> cl=Bar.class;
switch(cl.getSimpleName().hashCode()) {
case 70822:
if(cl==Foo.class) {
System.out.println("case Foo:");
}
break;
case 66547:
if(cl==Bar.class) {
System.out.println("case Baz:");
}
break;
case 66555:
if(cl==Baz.class) {
System.out.println("case Baz:");
}
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我使用简单名称而不是限定名称,因此此示例代码与包无关.但我认为,情况很清楚.可以switch为任何类型的对象实现有效的语句,该对象具有int可在编译时预测的常量属性.也就是说,也没有理由不支持long交换机.有很多方法可以int从long...中计算出合适的
所以还有另外一个重要决定要做.
这个功能真的有益吗?它看起来像代码味道 - 即使添加String支持也是有争议的.它不会增加新的可能性,因为您可以使用相同的if- else少数类或HashMap<Class,SomeHandlerType>更大的数字.并且它看起来并不像经常需要的东西,值得扩展语言规范,即使它只是一个必须添加的单句.
这些是推动语言设计的因素,但并不是思想和平衡无法改变.所以我并不是说未来的版本不可能获得这个功能.
但是,看看生成String switch代码的质量,我宁愿switches手动编写代码......