[java]话说枚举

本文深入探讨了Java中枚举类型的使用方法,包括如何使用接口存储常数,使用类存储常数,以及引入枚举类型带来的优势,如简单的常数设置、编译时类型检查、增强代码可读性等。同时,展示了枚举类型在实际编程中的应用,如通过枚举简化方法参数,实现代码的类型安全和高效。最后,通过实例演示了枚举类型在不同场景下的使用,如颜色、季节、性别、订单状态等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  程序中经常会使用到一些常数,如果这些常数是共享的,在java中可以定义一个类或接口来统一管理常数。其他对象从这些类或接口取用常数。如果需要修改常数则可以从这些类或接口上直接修改,而不用更改程序的其他部分。

  使用接口存储常数:

public interface Usual {
	public static final int TURN_LEFT=1;
	public static final int TURN_RIGHT=2;
	public static final int SHOT=3;
}

    在使用类存储常数时,直接在类中进行定义即可

public class Action{
              public static final  int  TURN_LEFT=1;
              ..............................
}

对于简单的常数设置,以上两种方法已经够用了。在DK.1.5引用了枚举类型,带来了极大的方便

  1 简单的常数设置

       2 获得编译时类型检查

       3 增强代码的可读性

 枚举类型的性质:

  1. 定义枚举类型其实就是在定义一个类,很多细节是由编译器搞定,所以从某种程度上,enum关键字的作用可以看作是interface和class
  2. 使用enum定义枚举类型时,定义出的类型是继承自java.lang.Enum类,而每个被枚举的成员其实就是定义的枚举类型的一个实例,他们都默认为final,无法改变常数名设置的值,它们也是public和static的成员,可以通过类名称直接使用它们。
  3. 枚举类型的构造函数不得是public和protected的构造函数,这是为了避免粗心的开发人员直接对枚举类型进行实例化
  4. 因值而异的类实现方式
  5. Enum覆盖了toString方法,默认返回字符串本身
  6. Enum提供了valueOf方法,这个方法和toString方法是相对应的,调用valueOf("name")将会返回enum.name,因此我们在重写toString方法的时候要注意到这一点,一般来说应该相对应的重写valueOf方法

 枚举类型的方法

  1. values()方法:取得所有的枚举成员实例,并以数组方式返回
  2. ordinal()方法:依枚举顺序得到位置索引,默认从0开始

  实例演示:

1 获得编译类型检查

定义一个接口

public interface Usual {
	public static final int TURN_LEFT=1;
	public static final int TURN_RIGHT=2;
	public static final int SHOT=3;
}

 

	public static void main(String[] args) throws IOException{
		doAction(Action.TURN_LEFT);
	}
	public  static void doAction(int action){
		switch(action){
		case Usual.TURN_LEFT:
			System.out.println("向左走");
			break;
		case Usual.TURN_RIGHT:
			System.out.println("向右走");
			break;
		case Usual.SHOT:
			System.out.println("射击");
			break;			
		}
		return;
	}

   这种做法本身是没错的,但是doAction方法接受的是int类型的常数,我们是没有能力阻止开发人员对其输入规定外的常数,也没有检查switch中枚举的值是不是正确的,因为参数action这是int类型而已,当然可以自行设计一些检查动作,这需要一些额外的工作。而枚举可以轻易的解决这些问题

定义一个枚举类

public enum Action {
	TURN_LEFT,
	TURN_RIGHT,
	SHOT;
	public String get(){
		switch(this.ordinal()){
		case 0:
			return "向右转";
		case 1:
			return "向左转";
		case 2:
			return "射击";
		default:
			return null;
		}
	}
}

 

	public static void main(String[] args) throws IOException{
		doAction(Action.TURN_LEFT);
	}
	public  static void doAction(Action action){
		switch(action){
		case TURN_LEFT:
			System.out.println("向左走");
			break;
		case TURN_RIGHT:
			System.out.println("向右走");
			break;
		case SHOT:
			System.out.println("射击");
			break;			
		}
		return;
	}

 这里doAction的参数类型是Action,如果对方法输入其他类型的变量,编译器就会报告错误。

 使用枚举类型还可以做进一步的检查,如果在switch中加入了不属于Action中枚举的值,编译器也会报告错误

	public  static void doAction(Action action){
		switch(action){
		case TURN_LEFT:
			System.out.println("向左走");
			break;
		case TURN_RIGHT:
			System.out.println("向右走");
			break;
		case SHOT:
			System.out.println("射击");
			break;			
		}
		case STOP:
			System.out.println("停止");
			break;
		return;
	}

 这是编译器会显示错误:unqualified enumeration constant name required

              case STOP:

            ^

2 枚举实例的简单应用

下面这段代码我是从http://www.cnblogs.com/linjiqin/archive/2011/02/11/1951632.html借鉴而来并做了很大的修改【自己想偷懒些】

/**
 * 枚举用法详解
 */
public class TestEnum {
    /**
     * 普通枚举
     */
    public enum ColorEnum {
        red, green, yellow, blue;
        public static int length(){
        	return ColorEnum.values().length;
        }//定义取得枚举成员的个数即长度
    }
    
    public enum SeasonEnum {
        //注:枚举写在最前面,否则编译出错
        spring, summer, autumn, winter;
        private final static String position = "test";
        public static SeasonEnum getSeason() {
            if ("test".equals(position))
                return spring;
            else
                return winter;
        }
    }
    
    /**
     * 性别
     * 
     * 实现带有构造器的枚举
     */
    public enum Gender{
        //通过括号赋值,而且必须带有一个参构造器和一个属性跟方法,否则编译出错
        //赋值必须都赋值或都不赋值,不能一部分赋值一部分不赋值;如果不赋值则不能写构造器,赋值编译也出错
        MAN("MAN"), WOMEN("WOMEN");    
        private final String value;
        //构造器默认也只能是private, 从而保证构造函数只能在内部使用
        Gender(String value) {
            this.value = value;
        }     
        public String getValue() {
            return value;
        }
    }
    
   /**
    * 
    * 实现带有抽象方法的枚举
    */
    public enum OrderState {
        /** 已取消 */
        CANCEL {public String getName(){return "已取消";}},
        /** 待审核 */
        WAITCONFIRM {public String getName(){return "待审核";}},
        /** 等待付款 */
        WAITPAYMENT {public String getName(){return "等待付款";}},
        /** 正在配货 */
        ADMEASUREPRODUCT {public String getName(){return "正在配货";}},
        /** 等待发货 */
        WAITDELIVER {public String getName(){return "等待发货";}},
        /** 已发货 */
        DELIVERED {public String getName(){return "已发货";}},
        /** 已收货 */
        RECEIVED {public String getName(){return "已收货";}};   
        public abstract String getName();//这里是很重要的
    }   
    
    public static void compareToSeasonEnum(SeasonEnum inputseasonenum){
    	System.out.println("请输入"+inputseasonenum);
    	for(SeasonEnum el:SeasonEnum.values()){
    		System.out.println(el.compareTo(inputseasonenum));
    	}
    }//比较SeasonEnum枚举对象间的顺序
    
    public static void main(String[] args) {
    	System.out.println("===============================");
        ColorEnum colorEnum = ColorEnum.blue;
        switch (colorEnum) {
        case red:
            System.out.println("color is red");
            break;
        case green:
            System.out.println("color is green");
            break;
        case yellow:
            System.out.println("color is yellow");
            break;
        case blue:
            System.out.println("color is blue");
            break;
        }
        System.out.println("===============================\n\n");
        
        
        System.out.println("=====遍历ColorEnum枚举中的值====");
        for(ColorEnum color : ColorEnum.values()){
            System.out.println(color);
        }
        System.out.println("===============================\n\n");
        

        System.out.println("====ColorEnum枚举中的值有"+ColorEnum.length()+"个====");
        System.out.println(ColorEnum.red.ordinal());//0
        System.out.println(ColorEnum.green.ordinal());//1
        System.out.println(ColorEnum.yellow.ordinal());//2
        System.out.println(ColorEnum.blue.ordinal());//3
        System.out.println(ColorEnum.red.compareTo(ColorEnum.green));//-1
        System.out.println("===============================\n\n");

        
        System.out.println("===============================");
        System.out.println("季节为" + SeasonEnum.getSeason());
        System.out.println("===============================\n\n");
        
        
        System.out.println("===============================");    
        for(Gender gender : Gender.values()){
            System.out.println(gender.value);
        }
        System.out.println("===============================\n\n");

        
        System.out.println("===============================");
        for(OrderState order : OrderState.values()){
            System.out.println(order.getName());
        }
        System.out.println("===============================\n\n");
        
        
        System.out.println("========valueOf方法应用========");
        //静态的valueOf方法可以让指定的字符串尝试转换为枚举实例
        compareToSeasonEnum(SeasonEnum.valueOf("winter"));
        System.out.println("===============================\n\n");
      
        System.out.println("******EnumSet的用法********");  
        // EnumSet的使用 
        EnumSet<ColorEnum> stateSet = EnumSet.allOf(ColorEnum.class); 
        for (ColorEnum s : stateSet) { 
            System.out.println(s); 
        } 

 

System.out.println("******EnumSet的用法********");  
        // EnumSet的使用  
        EnumSet<ColorEnum> stateSet = EnumSet.allOf(ColorEnum.class);  
        for (ColorEnum s : stateSet) {  
            System.out.println(s);  
        }  
          
        System.out.println("******EnumMap的用法********");  
        //EnumMap的使用  
        EnumMap stateMap = new EnumMap(ColorEnum.class);  
        stateMap.put(ColorEnum.red, "is red");  
        stateMap.put(ColorEnum.green, "is green");  
        stateMap.put(ColorEnum.yellow, "is yellow"); 
        stateMap.put(ColorEnum.blue, "is blue"); 
        for (ColorEnum s : ColorEnum.values()) {  
            System.out.println(s.name() + ":" + stateMap.get(s));  
        }
    }
    
}

 

运行结果:

===============================
color is blue
===============================


=====遍历ColorEnum枚举中的值====
red
green
yellow
blue
===============================


====ColorEnum枚举中的值有4个====
0
1
2
3
-1
===============================


===============================
季节为spring
===============================


===============================
MAN
WOMEN
===============================


===============================
已取消
待审核
等待付款
正在配货
等待发货
已发货
已收货
===============================


========valueOf方法应用========
请输入winter
-3
-2
-1
0
===============================


******EnumSet的用法********
red
green
yellow
blue
******EnumMap的用法********
red:is red
green:is green
yellow:is yellow
blue:is blue

 总结:

抛开具体编程语言来看,枚举所具有的核心功能应该是:

◆类型安全(Type Safety) 
◆紧凑有效的枚举数值定义(Compact, Efficient Declaration of Enumerated Values) 
◆无缝的和程序其它部分的交互操作(Seamless integration with other language features) 
◆运行的高效率(Runtime efficiency)

1.类型安全

枚举的申明创建了一个新的类型。它不同于其他的已有类型,包括原始类型(整数,浮点数等等)和当前作用域(Scope)内的其它的枚举类型。当你对函数的参数进行赋值操作的时候,整数类型和枚举类型是不能互换的(除非是你进行显式的类型转换),编译器将强制这一点。

2. 紧凑有效的枚举数值定义

定义枚举的程序应该很简单。

3.无缝的和程序其它部分的交互操作

语言的运算符,如赋值,相等/大于/小于判断都应该支持枚举。枚举还应该支持数组下标以及witch/case语句中用来控制流程的操作。

4. 运行的高效率

枚举的运行效率应该和原始类型的整数一样高。在运行时不应该由于使用了枚举而导致性能比使用整数有所下降。如果一种语言满足这四点要求,那么我们可以说这种语言是真正的支持枚举。比如前面所说的Pascal,Ada,和C++。很明显,Java不是。

Java的创始人James Gosling是个资深的C++程序员,他很清楚什么是枚举。但似乎他有意的删除了Java的枚举能力。其原因我们不得而知。可能是他想强调和鼓励使用多态性(polymorphism),不鼓励使用多重分支。而多重分支往往是和枚举联合使用的。不管他的初衷如何,我们在Java中仍然需要枚举。

 

转载于:https://www.cnblogs.com/kycool/archive/2011/12/17/2290461.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值