为什么我们不能在 Java 7+ 中打开类?

2022-01-19 00:00:00 class switch-statement java-8 java java-7

在我看来,这样的 switch 语句会很有意义,但它会产生编译错误:

It seems to me that such a switch statement would make a lot of sense, but it gives a compile error :

public void m(Class c) {
   switch (c) {
       case SubClassOfC1.class : //do stuff; break;
       case SubClassOfC2.class : //do stuff; break;
   }
} 

但是,不支持打开类.是什么原因?

However, classes are not supported to switch on. What is the reason why?

我不是在尝试解决 instanceof,它实际上是在类级别,我需要执行一些操作,那里没有实例.

I am not trying to workaround instanceof, it's really at the class level that I got some operations to perform, no instances there.

编译错误在 SubClassOfC1 &SubClassOfC2 : 需要常量表达式.

The compile error is around SubClassOfC1 & SubClassOfC2 : constant expression required.

推荐答案

有趣的是,到目前为止所有的答案基本上都是在说因为规范是这么说的",这是正确的,但并不真正令人满意.在 Java 7 之前,String 是不允许使用的,这通常被视为刻在石头上.

Interestingly, all answers so far are basically saying "because the specification says so", which is correct but not really satisfying. Before Java 7, Strings were not allowed and that was often treated like being carved in stone.

但技术障碍不应推动语言设计.如果没有办法将其编译为高效的代码,它可能仍会被编译为等效的 if ... else ... 子句,并且在源代码简洁性方面仍然具有优势.对于 String 值,有一种有效的方法.只需切换不变的哈希码并对匹配候选执行 equals 检查.事实上,规范并没有强制使用哈希码,它可以是任何不变的 int 属性,例如长度或第一个字符,但每个 String 的值应该不同.

But technical obstacles shouldn’t drive language design. If there is no way to compile it to efficient code, it might still get compiled to the equivalent of if … else … clauses, and still have a win on source code brevity. In the case of String values, there is an efficient way. Just switch over the invariant hashcode and perform an equals check on the match candidate. In fact, the specification does not mandate to use the hash code, it could be any invariant int property, e.g. the length or the first character, but it’s value should be different for each String.

同样,Class 对象上的 switch 也是可能的.它的哈希码不保证相同,但每个类都有一个常量名和一个常量哈希码.例如.以下作品:

Similarly, a switch over Class objects is possible. It’s hash code is not guaranteed to be the same, but each class has a constant name with a constant hash code. E.g. the following works:

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;
        }
    }
}

我使用简单名称而不是限定名称,因此此示例代码与包无关.但我认为,情况很清楚.可以为任何具有可以在编译时预测的常量 int 属性的对象实现高效的 switch 语句.也就是说,也没有理由不支持 long 开关.有很多方法可以从 long...

I used the simple name instead of the qualified name, so that this example code is package independent. But I think, the picture is clear. It is possible to implement efficient switch statements for any kind of object which has a constant int property that can be predicted at compile time. That said, there is also no reason not to support long switches. There are plenty of ways to calculate a suitable int from a long

所以还有另一个重要的决定要做.

So there are another important decisions to make.

这个功能真的有好处吗?看起来像是代码异味——即使是添加 String 支持也是有争议的.它不会增加新的可能性,因为您可以使用 if-else 为少数类或 HashMap 对于更大的数字.而且它看起来并不像经常需要的东西,值得扩展语言规范,即使它只是一个必须添加的句子.

Is this feature really a benefit? It looks like code smell—even the addition of String support was controversial. It does not add new possibilities as you may do the same with if-else for a small number of classes or a HashMap<Class,SomeHandlerType> for bigger numbers. And it doesn’t really look like something that is needed so often, that it is worth expanding the language specification, even if it is just a single sentence that has to be added.

这些是推动语言设计的考虑因素,但并不是思想和平衡不能改变.所以我并不是说未来的版本不可能获得这个功能.

These are the considerations that drive the language design, but it’s not that minds and balances cannot change. So I’m not saying that’s impossible that a future version gets this feature.

不过,看看 生成的 String switch 代码的质量 我宁愿手动编写我的 switches...

But well, looking at the quality of generated String switch code I’d rather code my switches manually…

相关文章