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

2023-10-16 08:47:56 浏览数 (2)

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

switch语句基本定义:

代码语言:javascript复制
switch (表达式){
    case 值1: 
        语句体1;
        break;
    case 值2:
        语句体2;
        break;
    ...
        
    default:
        语句体n 1;
        break;
}

break在switch语句中的作用

关于breakswitch语句的使用可以参考这篇博客https://cloud.tencent.com/developer/article/2342385

表达式的取值

表达式的取值类型

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

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

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

基本类型的处理

int**数据类型**

代码语言:javascript复制
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;
    }

反编译后的代码

代码语言:javascript复制
byte byte0 = 2;
		switch (byte0)
		{
		case 1: // '01'
			System.out.println("first");
			break;

		case 2: // '02'
			System.out.println("second");
			break;

		case 3: // '03'
			System.out.println("second");
			break;

		default:
			System.out.println("null");
			break;
		}

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

char**类型的处理**

代码语言:javascript复制
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;
    }

反编译后的代码:

代码语言:javascript复制
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码来进行判断的。

包装类型的处理

代码语言:javascript复制
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;
    }

经过反编译后的代码是

代码语言:javascript复制
Integer integer = Integer.valueOf(4);
		switch (integer.intValue())
		{
		case 1: // '01'
			System.out.println("first");
			break;

		case 2: // '02'
			System.out.println("second");
			break;

		case 3: // '03'
			System.out.println("second");
			break;

		default:
			System.out.println("null");
			break;
		}

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

枚举类型的处理

代码语言:javascript复制
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;
        }
    }
}

反编译:

代码语言:javascript复制
// 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: // '01'
			System.out.println("Stop");
			break;

		case 2: // '02'
			System.out.println("Pass");
			break;

		case 3: // '03'
			System.out.println("Wait");
			break;

		default:
			System.out.println("null");
			break;
		}
	}
}

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

String类型的处理

代码语言:javascript复制
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;
        }
    }
}

反编译后:

代码语言:javascript复制
// 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: // ''
			System.out.println("红色");
			break;

		case 1: // '01'
			System.out.println("绿色");
			break;

		case 2: // '02'
			System.out.println("黄色");
			break;

		default:
			System.out.println("null");
			break;
		}
	}
}

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

0 人点赞