Why can't we switch on classes in Java 7+?

前端 未结 5 1904
故里飘歌
故里飘歌 2020-12-30 13:35

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 S         


        
5条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-30 14:09

    It's because we can only switch on Constant Expressions (§15.28) or Enum constants (§8.9.1).

    From the JLS:

    The type of the Expression must be char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (§8.9), or a compile-time error occurs.

    To imagine why this might be, think about the optimization that occurs when the Java compiler is attempting to compile a switch statement.

    • It wants to absolutely, positively guarantee equality
    • It wants to be able to maximize performance (branch prediction) for all the cases
    • It wants to have an effective, consistent way of transforming the constant expressions into an integer lookup table (this is why long and float and double are not supported, but String is).

    Note that String being supported in switch statements was added only in Java 7. This is because the compiler uses a behind the scenes conversion of switch String to switch int, as detailed in this article. Quick summary:

    This code:

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

    Becomes this code:

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

    We can't reliably turn Class objects into ints the same way. Class doesn't override hashCode, it uses System.identityHashCode.

    Note also that the same class is not always the same Class, if it has been loaded with a different ClassLoader.

提交回复
热议问题