Java基础--枚举

版权声明:转载请取得博主同意 https://blog.csdn.net/weixin_43050247/article/details/89214313

本文主要讲解Java枚举的使用以及与使用常量的区别,由于本人水平有限,写作之前参考了几位大神的文章,对枚举的应用有了更深的理解。特记录下本文章,以供自己翻阅。
参考文章地址:
https://blog.csdn.net/zyhlwzy/article/details/79045066
https://blog.csdn.net/myzksky/article/details/81150199
https://blog.csdn.net/yin_pisces/article/details/52050427

一、版本历史

枚举(Enum)是JDK1.5版本新增的特性,1.5版本新增的特性还有泛型,For-each。JDK 1.6版本之后,switch case语句支持枚举类型的判断。

二、什么是枚举

枚举(Enum)是一种特殊的数据类型,它即是一种类(class)类型又比这个类型多了些特殊的约束。这些约束使其类更加的安全,方便使用。

1.创建一个枚举类

enum UserType{
    USER("USER","内部用户",1),CUSTOMER("CUSTOMER","消费者",2),PARTNER("PARTNER","合作商",3);
    private String userType;
   	private String typeName;
    private Integer typeIndex;

    private UserType(String userType,String typeName,Integer typeIndex){
       this.userType=userType;
       this.typeName=typeName;
       this.typeIndex=typeIndex;
    }
	// get set 方法
	
    @Override  
    public String toString() {  
        return this.userType+"_"+this.typeName;  

	};
	System.out.println(UserType.USER.getTypeName());  // 内部用户
    System.out.println(UserType.USER);	// USER  			没有复写toString()方法
    System.out.println(UserType.USER);	// USER_内部用户   	复写了toString()方法

枚举是一个特殊的类,它也有实例字段、构造器和方法。默认无参构造器不能够被声明并且所有的构造器必须被private修饰,枚举实例用","隔开,序列的最后用";"结束

创建一个枚举类要使用关键字 enum,隐藏的含义为该枚举类自动继承了java.lang.Enum<T>(抽象泛型类),只能实现接口而不能继承,Java编译器在编译时做了这个转换

enum UserType extends Eunum<UserType>{
    // something
};

实际上每一个继承自Enum<T>的枚举允许定义泛型类、接口和方法,通过这种方式可以让枚举类型的实例参数化或者类型参数化。比如:

public<T extends Enum< ? >> void performAction(final T instance) {
    // Perform some action here
}

在上面的声明中,类型T被约定为任意枚举类型的实例并且Java编译器将会对其做验证

2.实现接口

interface IsUser{
	boolean ifUser();
}

两种实现方式:

enum UserType implements IsUser{
	 USER("USER",true),CUSTOMER("CUSTOMER",true)	
	private String userType;
	private boolean isUser;
	
	UserType(String userType,boolean isUser){
		this.userType=userType;
		this.isUser=isUser;
	}
	boolean ifUser(){
		return this.isUser;
	}
}

System.out.println(UserType.USER.isUser());  //true

enum UserType implements IsUser{
	 USER("USER"){
        @Override
        public boolean isUser() {
            return true;
        }
    },CUSTOMER("CUSTOMER"){
    	 @Override
        public boolean isUser() {
            return false;
        }
    };
	private String userType;
	private boolean isUser;
	
	UserType(String userType,boolean isUser){
		this.userType=userType;
		this.isUser=isUser;
	}
}

System.out.println(UserType.USER.isUser());  //true

③使用接口组织枚举


public interface IsUser{  
    enum UserType implements IsUser{  
        USER,CUSTOMER;  
    }   
}

System.out.println(IsUser.UserType.USER);  // USER

3.枚举中的方法

基础类 Enum<T>为自动继承它的枚举实例提供了一些非常有用的方法。

方法 描述
String name() 返回枚举声明声明的枚举常量的名称
int ordinal() 返回枚举常量的次序(即枚举声明时的位置,初始常量分配的位置是0)

Java编译器为每个枚举类型自动生成两个更有用的静态方法(让我们将这个特殊的枚举类型假设为T)。

方法 描述
T[] values() 返回枚举T所声明的所有常量
T valueOf(String name) 返回指定名称的枚举常量
 System.out.println(UserType.valueOf("USER"));		// 调用toString方法 
 System.out.println(UserType.USER.ordinal());		// 0

上面代码中valueOf()的参数值为 实例名的字符串形式不是该实例的变量值

4.专用集合EnumSet和EnumMap

和所有其他类一样,枚举的实例也可以和标准Java集合库一起使用。然而,某些集合类型针对枚举做了优化,并且在大多数情况下推荐使用这些优化过后的集合代替通用的集合。

我们首先来看一下EnumSet集合。EnumSet集合是常规的集合优化过后高效存储枚举类型的一个集合,EnumSet不能够使用构造器进行实例化,但是它提供了很多非常有用的工厂方法。

// allOf工厂方法创建的EnumSet<T>实例就包含了所有枚举类型所枚举的常量:
final Set<DaysOfTheWeek> enumSetAll = EnumSet.allOf(DaysOfTheWeek.class);

//noneOf工厂方法创建的是一个空的EnumSet<T>实例
final Set<DaysOfTheWeek> enumSetNone = EnumSet.noneOf(DaysOfTheWeek.class);

//使用of工厂方法,可以指定枚举类型中那些枚举常量应该包含在EnumSet<T>中:
final Set< DaysOfTheWeek > enumSetSome = EnumSet.of(
    DaysOfTheWeek.SUNDAY,
    DaysOfTheWeek.SATURDAY
);

EnumMap<T, ?>是最接近于一般的map的,唯一的不同就是EnumMap<T, ?>的key是枚举类型的枚举常量

final Map<DaysOfTheWeek, String> enumMap = new EnumMap<>(UserType.class);
enumMap.put(UserType.USER, "Lundi");

三、枚举和常量的比较

使用常量时

  • 常量作为参数时,是String,int等弱类型,开发人员可以传入没有在常量接口里定义的值,这个问题无法通过编译器发现。
  • 由于开发人员可以直接写常量,所以不能用==对比,只能用equals对比,不能优化性能。
  • 开发人员没有参考资料时,不可能知道某个int类型的参数到底应该赋什么内容。
  • 编译时,是直接把常量的值编译到类的二进制代码里,常量的值在升级中变化后,需要重新编译引用常量的类,因为里面存的是旧值。
  • 如果常量类的构造器不私有,无法限制开发员继承/实现接口,开发员能够在子接口里继续添加常量.而这些常量可能得不到祖先层的支持。

使用枚举时

  • 私有构造函数,避免被继承和扩展。
  • 定义方法的参数时,必须用枚举常量类类型,如上面的Constant,这样就转变成了强类型,不会出现弱类型引用的问题。
  • 常量值地址唯一,可以用==直接对比,性能会有提高。
  • 编译时,没有把常量值编译到代码里,即使常量的值发生变化,也不会影响引用常量的类。

猜你喜欢

转载自blog.csdn.net/weixin_43050247/article/details/89214313