Java 2:枚举
2016-12-05 01:09
134 查看
1 基本使用
枚举里定义了一组常量,并赋给常量一个类型,及类和对象的行为。package com.cowthan.enum2; public enum Planet { MERCURY(3.302e+23, 2.439e6), //水星 VENUS(4.869e+24, 6.052e6), //金星 EARTH(5.975e+24, 6.378e6), // MARS(6.419e+23, 3.393e6), //火星 JUPITER(1.899e+27, 7.149e7), //木星 SATURN(5.685e+26, 6.027e7), //土星 URANUS(8.683e+25, 2.556e7), //天王星 NEPTUNE(1.024e+26, 2.477e7); //海王星 /* 枚举天生不可变,因此所有域都应该是final的 */ private final double mass; // kg private final double radius; // meter private final double surfaceGravity; // m/s^2 public boolean fuck = false; private static final double G = 6.67300E-11; Planet(double mass, double radius) { this.mass = mass; this.radius = radius; surfaceGravity = G * mass / (radius * radius); } public double mass() {return mass;} public double radius() { return radius;} public double surfaceGravity() { return surfaceGravity;} public double surfaceWeight(double mass){ return mass * surfaceGravity; } public static void main(String[] args) { double earthWeight = 100; //kg double mass = earthWeight / Planet.EARTH.surfaceGravity(); for(Planet p: Planet.values()){ System.out.printf("Weight on %s is %f%n", p, p.surfaceWeight(mass)); } } }
public enum Operation_1 { PLUS, MINUS, TIMES, DIVIDE; public double apply(double x, double y){ switch(this){ case PLUS: return x+y; case MINUS: return x-y; case TIMES: return x*y; case DIVIDE: return x/y; } throw new AssertionError("unknown op: " + this); ///没有这句,编译不会通过 } }
2 抽象方法
package com.cowthan.enum2; /** * 特定于常量的方法实现 * */ public enum Operation { PLUS("+") { @Override double apply(double x, double y) { return x + y; } }, MINUS("-") { @Override double apply(double x, double y) { return x - y; } }, TIMES("*") { @Override double apply(double x, double y) { return x * y; } }, DIVIDE("/") { @Override double apply(double x, double y) { return x / y; } }; private final String symbol; private Operation(String symbol) { this.symbol = symbol; } abstract double apply(double x, double y); @Override public String toString() { return symbol; } }
3 enum操作
enum的静态方法: Week[] values():返回所有常量的数组 Week valueOf(String):根据常量名,获得枚举常量 enum的实例方法: name():获取常量名 ordinal():获取枚举常量在类型中的数字位置,从0开始 特别注意: ordinal()是内置的,这个是序数,是为EnumSet和EnumMap设计的,程序员不应该依赖这个方法做有关下标的事 你应该用实例域代替序数,例如MONDAY(1)
4 EnumSet代替位域: 枚举的集合
什么是位域呢,就是常见的flag模式,或者标志位模式public class Text{ public static final int STYLE_BOLD = 1 << 0; //1 0001 public static final int STYLE_ITALIC = 1 << 1; //2 0010 public static final int STYLE_UNDERLINE = 1 << 2; //4 0100 public static final int STYLE_STRIKETHROUGH = 1 << 3; //8 1000 public void applyStyles(int styles){ } } text.applyStyles(STYLE_BOLD | STYLE_ITALIC); OR运算符可以将几个常量合并到一个集合中, 这就叫位域(bit field),可以认为位域是标志位的集合 EnumSet可以用单个long来实现,性能比得上位域
改为使用位域:
public class Text{ public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH } //任何Set都可以传进来,但EnumSet是最佳的 public void applyStyles(Set<Style> styles){ } } 怎么调用:text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
5 EnumMap代替序数索引
避免使用enum.ordinal()作为数组下标,如果想根据enum的序数快速定位枚举,应该用EnumMapEnumMap:键是枚举的Map
Map<Week, Set<Course>> courses = new EnumMap<Week, Set<Course>>(Week.class); for(Week w: Week.values()){ courses.put(w, new HashSet<Course>>); }
指定了EnumMap的key类型之后,由于enum的常量个数是固定的,
所以Enum最多有几个键也是固定的,
所以可以实现完美哈希
6 枚举和String
Enum.valueOf(s)方法,根据常量名的字符串直接得到枚举常量如果toString被覆盖(默认返回常量名),则你需要下面这段代码来进行字符串和枚举常量的映射:
public enum Week { Monday; public String toString() { if(this == Week.Monday){ return "周一"; } return ""; } private static final Map<String, Week> stringToEnum = new HashMap<>(); static{ for(Week w: Week.values()){ stringToEnum.put(w.toString(), w); } } public static void main(String[] args) { Week monday = Week.valueOf("Monday"); ///转换枚举常量name System.out.println(monday); Week monday2 = Week.stringToEnum.get("周一"); ///转换自定义字符串 System.out.println(monday2); } }
7 例子
策略枚举策略模式的枚举版,普通的策略模式是一个接口,具体实现类来提供具体算法
需求:算每天的工资
每天上班标准是8小时,工资固定
超出部分是加班,工资1.5倍
平时超出8小时算加班
周末全算加班
你分析一下这个需求:
1 上班的这一天可能是工作日,周末,也有可能是其他节假日,而且加班工资可能也不一样
2 所以先定义个工作日类型,也可以看做薪资类型,主要处理加班工资的问题,这里是PayType
public enum PayRollDay { MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY(PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FRIDAY(PayType.WEEKDAY), SATURDAY(PayType.WEEKEND), SUBDAY(PayType.WEEKEND); private final PayType payType; PayRollDay(PayType payType){ this.payType = payType; } double pay(double hoursWorked, double payRate){ return payType.pay(hoursWorked, payRate); } private enum PayType{ WEEKDAY{ double overtimePay(double hours, double payRate){ return hours <= HOURS_PER_SHIFT ? 0 : (hours - HOURS_PER_SHIFT) * payRate / 2; } }, WEEKEND{ double overtimePay(double hours, double payRate){ return (hours) * payRate / 2; } }; private static final int HOURS_PER_SHIFT = 8; abstract double overtimePay(double hrs, double parRate); double pay(double hoursWorked, double payRate){ double basePay = hoursWorked * payRate; return basePay + overtimePay(hoursWorked, payRate); } } }
8 安卓里的枚举
安卓开发里之前一直有个说法,就是谷歌本身不建议使用枚举,因为枚举比不用枚举性能耗费高,但其实不用很在意这里的性能问题,如果你觉得用枚举确实能让代码清晰,那就用。使用枚举一般情况下是给常量以类型,从而在方法参数里可以加类型限制,关于这一点,有个替代方案,就是@IntDef,这个就是谷歌为了让大家不使用枚举提供的注解,主要用于给int类型的常量提供编译期类型检查。
这个使用不是很复杂,代码如下:
代码来源:https://my.oschina.net/Bruce370/blog/499279?p={{page}}
public class MainActivity extends Activity { //先定义 常量 public static final int SUNDAY = 0; public static final int MONDAY = 1; public static final int TUESDAY = 2; public static final int WEDNESDAY = 3; public static final int THURSDAY = 4; public static final int FRIDAY = 5; public static final int SATURDAY = 6; //用 @IntDef "包住" 常量; // @Retention 定义策略 // 声明构造器 @IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY}) @Retention(RetentionPolicy.SOURCE) public @interface WeekDays {} @WeekDays int currentDay = SUNDAY; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setCurrentDay(WEDNESDAY); //声明变量 @WeekDays int today = getCurrentDay(); switch (today){ case SUNDAY: break; case MONDAY: break; case TUESDAY: break; case WEDNESDAY: break; case THURSDAY: break; case FRIDAY: break; case SATURDAY: break; default: break; } } public void setCurrentDay(@WeekDays int currentDay) { this.currentDay = currentDay; } @WeekDays public int getCurrentDay() { return currentDay; } } 注意: compile 'com.android.support:support-annotations:22.0.0'
相关文章推荐
- JAVA 枚举
- Java中使用枚举
- Java中如何由枚举常量的ordinal值获得枚举常量对象
- 简述java枚举类型
- java中的枚举
- java枚举
- 定义java的枚举变量
- Java中的枚举类型
- 9.Java中的集合、枚举、泛型【下】
- java新功能之一枚举
- 再谈在Java中使用枚举
- Java基础-枚举的两种基本模式
- 深入探讨Java枚举的实现
- Java中枚举详解(1)
- Java枚举,酷! (原文发表于2006-04-25 下午01:13:48)
- java类型安全枚举与反射机制相结合的应用 作者:封宇
- 关于Collection.sort和java的枚举
- Java中如何由枚举常量的ordinal值获得枚举常量对象
- Java枚举工具类ValuedEnum用法
- JavaAnnotation与枚举