Java 枚举

定义

enum 的全称为 enumeration, 是 JDK 1.5 中引入的新特性,存放在 java.lang 包中。

它既是一种类(class)类型却又比类类型多了些特殊的约束,但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。

 

关键词enum可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件来使用 。

《Java编程思想第四版》

源码

public abstract class Enum<E extends Enum<E>>  implements Comparable<E>, Serializable{}

在什么情况使用枚举?

当需要一个类的对象有限且固定,需要使用public static final 修饰的时候,可以使用枚举...

  枚举类更加直观,类型安全。使用常量会有以下几个缺陷:

  1. 类型不安全。若一个方法中要求传入季节这个参数,用常量的话,形参就是int类型,开发者传入任意类型的int类型值就行,但是如果是枚举类型的话,就只能传入枚举类中包含的对象。

  2. 没有命名空间。开发者要在命名的时候以SEASON_开头,这样另外一个开发者再看这段代码的时候,才知道这四个常量分别代表季节。

 

枚举

package enumcase;

public enum SeasonEnum {
    SPRING,SUMMER,FALL,WINTER;
}

1、enum 、class 、interface相同的存在

2、使用enum定义的枚举类默认继承了java.lang.Enum,而不是继承Object类。枚举类可以实现一个或多个接口。

3、枚举类的所有实例都必须放在第一行展示,不需使用new 关键字,不需显式调用构造器。自动添加public static final修饰。

4、使用enum定义、非抽象的枚举类默认使用final修饰,不可以被继承。

5、枚举类的构造器只能是私有的。

 

使用反编译工具编译后:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   SeasonEnum.java

package com.aozhi.enumTest;

//自定义的枚举基础了Enum
public final class SeasonEnum extends Enum
{

 //私有构造方法,这里调用了父类的构造方法,其中参数s对应了常量名,参数i代表枚举的一个顺序(这个顺序与枚举的声明顺序对应,用于oridinal()方法返回顺序值
    private SeasonEnum(String s, int i)
    {
        super(s, i);
    }

//返回存储枚举实例的数组的副本。values()方法通常用于foreach循环遍历枚举常量。
    public static SeasonEnum[] values()
    {
        SeasonEnum aseasonenum[];
        int i;
        SeasonEnum aseasonenum1[];
        System.arraycopy(aseasonenum = ENUM$VALUES, 0, aseasonenum1 = new SeasonEnum[i = aseasonenum.length], 0, i);
        return aseasonenum1;
    }

   //根据实例名获取实例
    public static SeasonEnum valueOf(String s)
    {
        return (SeasonEnum)Enum.valueOf(com/aozhi/enumTest/SeasonEnum, s);
    }

   //我们定义的枚举在这里声明了三个 SeasonEnum的常量对象引用,对象的实例化在static静态块中
    public static final SeasonEnum SPRING;
    public static final SeasonEnum SUMMER;
    public static final SeasonEnum FALL;
    public static final SeasonEnum WINTER;
    private static final SeasonEnum ENUM$VALUES[];

    static 
    {
        SPRING = new SeasonEnum("SPRING", 0);
        SUMMER = new SeasonEnum("SUMMER", 1);
        FALL = new SeasonEnum("FALL", 2);
        WINTER = new SeasonEnum("WINTER", 3);

//将所有枚举的实例存放在数组中
        ENUM$VALUES = (new SeasonEnum[] {
            SPRING, SUMMER, FALL, WINTER
        });
    }
}

 枚举类内也可以定义属性和方法,可是是静态的和非静态的。

如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例

package com.aozhi.enumTest;

public enum SeasonEnum {
    // SPRING,SUMMER,FALL,WINTER;
    //枚举类的所有实例都必须放在第一行展示
    SPRING("春天"),SUMMER("夏天"),FALL("秋天"),WINTER("冬天");
    
    private final String name;
    
    //当重载有参构造,就无法使用默认的无参构造
    private SeasonEnum(String name)
    {
        System.out.println("季节枚举构造");
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

执行结果:

 

说明:1、枚举中的所有实例必须放在枚举中的第一行的位置

            2、每个实例调用构造方法,进行初始化

            3、构造器需定义成私有的,这样就不能在别处申明此类的对象了。枚举类通常应该设计成不可变类,它的Field不应该被改变,这样会更安全,而且代码更加简洁。所以我们将Field用private final修饰。

 

 

枚举实现接口

枚举类可以实现一个或多个接口。与普通类一样,实现接口的时候需要实现接口中定义的所有方法,若没有完全实现,那这个枚举类就是抽象的,只是不需显式加上abstract修饰,系统化会默认加上。

package com.aozhi.enumTest;

public enum Operation {
    PLUS{

        @Override
        public double eval(double x, double y) {
            return x + y;
        }
        
    },
    MINUS{

        @Override
        public double eval(double x, double y) {
            return x - y;
        }
        
    },
    TIMES{

        @Override
        public double eval(double x, double y) {
            return x * y;
        }
        
    },
    DIVIDE{

        @Override
        public double eval(double x, double y) {
            return x / y;
        }
        
    };
    
    /**
     * 抽象方法,由不同的枚举值提供不同的实现。
     * @param x
     * @param y
     * @return
     */
    public abstract double eval(double x, double y);
    
    public static void main(String[] args) {
        System.out.println(Operation.PLUS.eval(10, 2));
        System.out.println(Operation.MINUS.eval(10, 2));
        System.out.println(Operation.TIMES.eval(10, 2));
        System.out.println(Operation.DIVIDE.eval(10, 2));
    }
}

Operatio类实际上是抽象的,不可以创建枚举值,所以此处在申明枚举值的时候,都实现了抽象方法,这其实是匿名内部类的实现,花括号部分是一个类体。我们可以看下编译以后的文件。

共生成了五个class文件,这样就证明了PLUS,MINUS,TIMES,DIVIDE是Operation的匿名内部类的实例。

来源:https://www.cnblogs.com/sister/p/4700702.html

由于Java单继承的原因,enum类并不能再继承其它类,但并不妨碍它实现接口,因此enum类同样是可以实现多接口的,如下:

package com.zejian.enumdemo;

/**
 * Created by zejian on 2017/5/8.
 * Blog : http://blog.csdn.net/javazejian [原文地址,请尊重原创]
 */

interface food{
    void eat();
}

interface sport{
    void run();
}

public enum EnumDemo2 implements food ,sport{
    FOOD,
    SPORT,
    ; //分号分隔

    @Override
    public void eat() {
        System.out.println("eat.....");
    }

    @Override
    public void run() {
        System.out.println("run.....");
    }
}

有时候,我们可能需要对一组数据进行分类,比如进行食物菜单分类而且希望这些菜单都属于food类型,appetizer(开胃菜)、mainCourse(主菜)、dessert(点心)、Coffee等,每种分类下有多种具体的菜式或食品,此时可以利用接口来组织,如下(代码引用自Thinking in Java):
 

public interface Food {
  enum Appetizer implements Food {
    SALAD, SOUP, SPRING_ROLLS;
  }
  enum MainCourse implements Food {
    LASAGNE, BURRITO, PAD_THAI,
    LENTILS, HUMMOUS, VINDALOO;
  }
  enum Dessert implements Food {
    TIRAMISU, GELATO, BLACK_FOREST_CAKE,
    FRUIT, CREME_CARAMEL;
  }
  enum Coffee implements Food {
    BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
    LATTE, CAPPUCCINO, TEA, HERB_TEA;
  }
}

public class TypeOfFood {
  public static void main(String[] args) {
    Food food = Appetizer.SALAD;
    food = MainCourse.LASAGNE;
    food = Dessert.GELATO;
    food = Coffee.CAPPUCCINO;
  }
} 
--------------------- 

 

通过这种方式可以很方便组织上述的情景,同时确保每种具体类型的食物也属于Food,现在我们利用一个枚举嵌套枚举的方式,把前面定义的菜谱存放到一个Meal菜单中,通过这种方式就可以统一管理菜单的数据了。

 

public enum Meal{
  APPETIZER(Food.Appetizer.class),
  MAINCOURSE(Food.MainCourse.class),
  DESSERT(Food.Dessert.class),
  COFFEE(Food.Coffee.class);
  private Food[] values;
  private Meal(Class<? extends Food> kind) {
    //通过class对象获取枚举实例
    values = kind.getEnumConstants();
  }
  public interface Food {
    enum Appetizer implements Food {
      SALAD, SOUP, SPRING_ROLLS;
    }
    enum MainCourse implements Food {
      LASAGNE, BURRITO, PAD_THAI,
      LENTILS, HUMMOUS, VINDALOO;
    }
    enum Dessert implements Food {
      TIRAMISU, GELATO, BLACK_FOREST_CAKE,
      FRUIT, CREME_CARAMEL;
    }
    enum Coffee implements Food {
      BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
      LATTE, CAPPUCCINO, TEA, HERB_TEA;
    }
  }
} 

博客地址:https://blog.csdn.net/javazejian/article/details/71333103

 

switch语句里的表达式可以是枚举值

  case表达式中直接写入枚举值,不需加入枚举类作为限定。

enum Signal {  
    GREEN, YELLOW, RED  
}  
public class TrafficLight {  
    Signal color = Signal.RED;  
    public void change() {  
        switch (color) {  
        case RED:  
            color = Signal.GREEN;  
            break;  
        case YELLOW:  
            color = Signal.RED;  
            break;  
        case GREEN:  
            color = Signal.YELLOW;  
            break;  
        }  
    }  
}

---------------------------------------------------------------小生是一条霸气的分割线------------------------------------------------------------------

package com.angus.testenum;
/**
  * <p>Title: TestEnum</p>  
  * <p>Description: </p>  
  * @author angus  
  * @date 2018年10月17日
 */
public class TestEnum {
	/**
	 * 
	  * <p>Title: Season</p>  
	  * <p>Description:简单的枚举类 </p>  
	  * @author angus  
	  * @date 2018年10月17日
	 */
	enum Season{
		SPRING,SUMMER,AUTUMN,WINTER 
	}
	/**
	 * 
	  * <p>Title: Color</p>  
	  * <p>Description:使用构造方法,给枚举赋值 </p>  
	  * @author angus  
	  * @date 2018年10月17日
	 */
	enum Color{
		RED("红色"),YELLOW("黄色"),BLUE("蓝色");
		
		private String name;
		private Color(String name) {
			this.name=name;
		}
		
		public String getName() {
			return this.name;
		}
		
		public static Color fromColorName(String colorName) {
			for (Color color : Color.values()) {
				if(colorName.equals(color.getName())) {
					//System.out.println("");
					return color;
				}
			}
			return null;
		}
	}
	
	private static void forEnum() {
		for (Season season : Season.values()) {
			System.out.println("season::"+season+",ordinal::"+season.ordinal());
		}
		
		System.out.println("==================小生是条霸气的分割线============================");
		for (Color color : Color.values()) {
			System.out.println("color::"+color+",colorName::"+color.name+",ordinal::"+color.ordinal());
		}
	
	}
	
	
	private static void useEnumInJava() {
		String colorName="黄色";
		Color color=	Color.fromColorName(colorName);
		if(color==(Color.YELLOW)) {
			System.out.println("This is same");
		}else {
			System.out.println("angus error");
		}
	}
	
	public static void main(String[] args) {
		forEnum();
		
		System.out.println("++++++++++++++++++小生是条霸气的分割线的弟弟++++++++++++++");
		useEnumInJava();
	}
}

结果::

枚举的实例末尾以分号“;”结尾

枚举的构造方法必须是私有的,不可像类一样在任何地方进行实例化new ,枚举的实例只能是在枚举内,枚举的实例是有限的,这种限制了范围的,在一些情况下的时候更为方便,简单 

 

 

___________________________________小生是条不那么讲究的分割线——————————————————————

枚举使用的规范:规范而已,开心就好

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值