Loading

switch表达式中可以用哪些类型

switch语句是一个很容易忽略的语法点,在表达式支持的类型上也犯过很多错,今天就来整理一下

switch语句基本定义:

switch (表达式){
    case 值1: 
        语句体1;
        break;
    case 值2:
        语句体2;
        break;
    ...
        
    default:
        语句体n+1;
        break;
}

break在switch语句中的作用

关于breakswitch语句的使用可以参考这篇博客https://www.cnblogs.com/EthanWong/p/13190595.html

表达式的取值

表达式的取值类型

  1. 在JDK6及以前,表达式只能是一个常量表达式或枚举常量。所以表达式的取值可以是:
    • byteshortintchar四种基本类型,以及其包装类型
    • Enum枚举类型
  2. 在JDK7以后新增支持String类型

编译器对表达式取值的处理

虽然随着JDK版本迭代,支持的新类型越来越多,但是在编译的字节码层次,switch语句还是只能支持基本的四种类型。

  1. 基本类型的处理

    int数据类型

    int a = 2;
    switch (a)
        {
            case 1: 
                System.out.println("first");
                break;
    
            case 2: 
                System.out.println("second");
                break;
    
            case 3: 
                System.out.println("second");
                break;
    
            default:
                System.out.println("null");
                break;
        }
    

    反编译后的代码

    byte byte0 = 2;
    		switch (byte0)
    		{
    		case 1: // '\001'
    			System.out.println("first");
    			break;
    
    		case 2: // '\002'
    			System.out.println("second");
    			break;
    
    		case 3: // '\003'
    			System.out.println("second");
    			break;
    
    		default:
    			System.out.println("null");
    			break;
    		}
    

    ​ 其实从这里就可以看出,正是因为intbytecharshort之间可以隐式转换。所以可以直接支持其对应的四种包装类型

    char类型的处理

    char c = '2';
    switch (c)
        {
            case '1': 
                System.out.println("first");
                break;
    
            case '2': 
                System.out.println("second");
                break;
    
            case '3': 
                System.out.println("second");
                break;
    
            default:
                System.out.println("null");
                break;
        }
    

    反编译后的代码:

    byte byte0 = 50;
    		switch (byte0)
    		{
    		case 49: // '1'
    			System.out.println("first");
    			break;
    
    		case 50: // '2'
    			System.out.println("second");
    			break;
    
    		case 51: // '3'
    			System.out.println("second");
    			break;
    
    		default:
    			System.out.println("null");
    			break;
    		}
    

    从代码来看,底层是通过比较字符的ASCII码来进行判断的。

  2. 包装类型的处理

    Integer I = 4;
    switch (I)
        {
            case 1: 
                System.out.println("first");
                break;
    
            case 2: 
                System.out.println("second");
                break;
    
            case 3: 
                System.out.println("second");
                break;
    
            default:
                System.out.println("null");
                break;
        }
    

    经过反编译后的代码是

    Integer integer = Integer.valueOf(4);
    		switch (integer.intValue())
    		{
    		case 1: // '\001'
    			System.out.println("first");
    			break;
    
    		case 2: // '\002'
    			System.out.println("second");
    			break;
    
    		case 3: // '\003'
    			System.out.println("second");
    			break;
    
    		default:
    			System.out.println("null");
    			break;
    		}
    

    从反编译的代码中可以看出,Integer装箱的时候自动调用Integervalueof(int)方法,拆箱的时候是自动调用IntegerintValue方法。对应到其他包装类型和Integer也类似。

  3. 枚举类型的处理

    public enum ColorEnum{
        RED,GREEN,YELLOW;
    }
    
    public class EnumTest{
        public static void main(String args[]){
            ColorEnum color = ColorEnum.YELLOW;
            switch(color){
                case RED:
                    System.out.println("Stop");
                    break;
                case GREEN:
                    System.out.println("Pass");
                    break;
                case YELLOW:
                    System.out.println("Wait");
                    break;
                default:
                    System.out.println("null");
                    break;
            }
        }
    }
    

    反编译:

    // Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
    // Jad home page: http://kpdus.tripod.com/jad.html
    // Decompiler options: packimports(3) fieldsfirst ansi space 
    // Source File Name:   EnumTest.java
    
    import java.io.PrintStream;
    
    public class EnumTest
    {
    
    	public EnumTest()
    	{
    	}
    
    	public static void main(String args[])
    	{
    		ColorEnum colorenum = ColorEnum.YELLOW;
    		static class 1
    		{
    
    			static final int $SwitchMap$ColorEnum[];
    			//自动生成int数组,通过编号来表示枚举
    			static 
    			{
    				$SwitchMap$ColorEnum = new int[ColorEnum.values().length];
    				try
    				{
    					$SwitchMap$ColorEnum[ColorEnum.RED.ordinal()] = 1;
    				}
    				catch (NoSuchFieldError nosuchfielderror) { }
    				try
    				{
    					$SwitchMap$ColorEnum[ColorEnum.GREEN.ordinal()] = 2;
    				}
    				catch (NoSuchFieldError nosuchfielderror1) { }
    				try
    				{
    					$SwitchMap$ColorEnum[ColorEnum.YELLOW.ordinal()] = 3;
    				}
    				catch (NoSuchFieldError nosuchfielderror2) { }
    			}
    		}
    
    		switch (1..SwitchMap.ColorEnum[colorenum.ordinal()])
    		{
    		case 1: // '\001'
    			System.out.println("Stop");
    			break;
    
    		case 2: // '\002'
    			System.out.println("Pass");
    			break;
    
    		case 3: // '\003'
    			System.out.println("Wait");
    			break;
    
    		default:
    			System.out.println("null");
    			break;
    		}
    	}
    }
    

    从反编译的代码可以看出,底层通过创建$SwitchMap$ColorEnum[]int数组,并通过数组的编号来表示枚举。

  4. String类型的处理

    public class StringTest{
        public static void main (String args[]){
            String s = "RED";
            switch(s){
                case RED:
                    System.out.println("红色");
                    break;
                case GREEN:
                    System.out.println("绿色");
                    break;
                case YELLOW:
                    System.out.println("黄色");
                    break;
                default:
                    System.out.println("null");
                    break;
            }
        }
    }
    

    反编译后:

    // Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
    // Jad home page: http://kpdus.tripod.com/jad.html
    // Decompiler options: packimports(3) fieldsfirst ansi space 
    // Source File Name:   StringTest.java
    
    import java.io.PrintStream;
    
    public class StringTest
    {
    
    	public StringTest()
    	{
    	}
    
    	public static void main(String args[])
    	{
    		String s = "RED";
    		String s1 = s;//创建string对象
    		byte byte0 = -1;
    		switch (s1.hashCode())
    		{
    		case 81009: //string常量用hash值表示
    			if (s1.equals("RED")) //避免hash碰撞,用equals辅助判断
    				byte0 = 0;
    			break;
    
    		case 68081379: 
    			if (s1.equals("GREEN"))
    				byte0 = 1;
    			break;
    
    		case -1680910220: 
    			if (s1.equals("YELLOW"))
    				byte0 = 2;
    			break;
    		}
    		switch (byte0)
    		{
    		case 0: // '\0'
    			System.out.println("红色");
    			break;
    
    		case 1: // '\001'
    			System.out.println("绿色");
    			break;
    
    		case 2: // '\002'
    			System.out.println("黄色");
    			break;
    
    		default:
    			System.out.println("null");
    			break;
    		}
    	}
    }
    

    从代码中可以看出,在对String类型的处理中,是通过对常量的hash值和equals方法来判断比较。

posted @ 2020-06-26 12:22  归思君  阅读(2822)  评论(0编辑  收藏  举报