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方法來判斷比較。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM