Java枚举

      枚举类型始于Java5,可能很多同学做了很多年Java开发都没有用到过枚举或者只用于常量标识,而一般很多项目中的常量标识都是String或者int,而使用String和int所带来的风险之一就是非法参数(当然还有参数比较)。那枚举是什么?枚举有什么用呢?

枚举是什么,枚举的实质

假设性别枚举类:男、女、未知,代码如下

public enum Sex {
    MALE, FEMALE, UNKNOW
}

然后你可能见过下面这样子也是可以的,可能会想这尼玛什么鬼?

public enum Sex {
    MALE(), FEMALE(), UNKNOW()
}

其实枚举的本质还是类,枚举的成员就是声明的静态实例,口说无凭直接javap开搞,javap Sex.class命令执行结果

public final class com.newstart.demo._enum.Sex extends   java.lang.Enum<com.newstart.demo._enum.Sex> {

  public static final com.newstart.demo._enum.Sex MALE;

  public static final com.newstart.demo._enum.Sex FEMALE;

  public static final com.newstart.demo._enum.Sex UNKNOW;

  public static com.newstart.demo._enum.Sex[] values();

  public static com.newstart.demo._enum.Sex valueOf(java.lang.String);

  static {};

}

可以看到Sex类继承自java.lang.Enum,类中有三个静态成员变量,都是Sex类的实例而且都是final的。我们一般声明静态常量不也是这样声明的吗?枚举的设计初衷就是提供一组常量。

 

枚举有什么用,怎么用

  • 作为常量使用,比如你要限制某个方法的入参只能是MALE, FEMALE, UNKNOW三者之一

public enum Sex {
    MALE, FEMALE, UNKNOW
}
 
  • switch代码块,其实就是用与对比和判断

public void choose(Sex sex) {
    switch (sex) {
        default:
        case FEMALE:
            //do something
            break;
        case MALE:
            //do something
            break;
        case UNKNOW:
            //do something
            break;
    }
}
  • 自定义字段,添加方法

public enum Sex {
    MALE(1, "男"), 
    FEMALE(2, "女"), 
    UNKNOW(3, "未知");
    
    //代码,比如你数据库实际存1 2 3
    private int code;
    //描述
    private String description;

    Sex(int code, String description) {
        this.code = code;
        this.description = description;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

这个时候可以查看编译后的class文件,发现Sex类的构造方法是这样的:

  private Sex(int code, String description) {

    this.code = code;

    this.description = description;

  }

对private,也就是说外部是new不了Sex对象的,上述代码在实际情况中应该去掉setter,这个有违枚举的设计初衷,所以如果可以通过外部来改变它是非常糟糕的设计。

  • 单例模式

上述提到枚举的的构造方法是私有的,既然是私有的就可以用来构造单例,简单粗暴

public enum Singleton {
    INSTANCE;

    private String prefix;

    Singleton() {
        this.prefix = "枚举说";
    }

    public void say(String str) {
        System.out.println(this.prefix +
                           ":" + str);
    }

    public static void main(String[] args) {
        Singleton.INSTANCE.say("代码如此多娇");
    }
}
  • 实现接口,因为本质上就是类,所以可以实现接口,但是不能继承,因为枚举都是继承至java.lang.Enum

public interface Likeable {
    /**
     * 喜欢什么性别
     *
     * @return
     */
    Sex like();
}

 

public enum Sex 
               implements Likeable {
    MALE {
        @Override
        public Sex like() {
            return FEMALE;
        }
    },
    FEMALE {
        @Override
        public Sex like() {
            return MALE;
        }
    },
    UNKNOW {
        @Override
        public Sex like() {
            return UNKNOW;
        }
    }
}

想知道更详细的介绍和用法可以阅读《effective java》章节“用接口模拟可伸缩枚举”。

  • 使用抽象方法,为每个枚举成员提供不同的行为

public enum Sex {
    MALE {
        @Override
        Sex like() {
            return FEMALE;
        }
    },
    FEMALE {
        @Override
        Sex like() {
            return MALE;
        }
    },
    UNKNOW {
        @Override
        Sex like() {
            return UNKNOW;
        }
    };

    /**
     * 喜欢什么性别
     *
     * @return
     */
    abstract Sex like();
}
  • 枚举集合

       java.util.EnumSet和java.util.EnumMap,看到Set和Map就明白是什么意思了。EnumSet提供了很多静态方法创建Set集合,EnumMap中的key必须是Enum类型。

    还有很多等待探究。

posted @ 2017-05-25 09:59  代码如此多娇  阅读(386)  评论(0编辑  收藏  举报