枚举和注解_EJ,枚举和注解

作者:计算机知识

第30条: 用enum代替int常量

枚举类型是指由一组固定的常量组成合法值得类型。比如一年中的季节,太阳系中的行星或壹副牌中的花色。在开垦中我们日常在类使用static final来定义三个int常量。这种方法存在多数欠缺,在项目安全性和利用方便性方面从未别的赞助。

看多少个枚举类型的事例,体会一下其用法。

太阳系中的行星:

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);
    private final double mass;
    private final double radius;
    private final double surfaceGravity;
    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 class WeightTable {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        double earthWeight = 70;
        double mass = earthWeight / Planet.EARTH.surfaceGravity();
        for(Planet p : Planet.values()){
            System.out.printf("Weight on %s is %f%n", p, p.surfaceWeight(mass));
        }
    }

}

2个操作符的例证:

public enum Operation {
    PLUS, MINUS, TIMES, DIVIDE;
    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);
    }
}

运用switch格局明显缺乏好,大家革新一下。

public enum Operation2 {
    PLUS(" ")    {double apply(double x, double y){return x   y;}}, 
    MINUS("-") {double apply(double x, double y){return x - y;}}, 
    TIMES("*")  {double apply(double x, double y){return x * y;}}, 
    DIVIDE("/") {double apply(double x, double y){return x / y;}};
    private final String symbol;
    Operation2(String symbol){
        this.symbol = symbol;
    }
    @Override
    public String toString() {
        return symbol;
    }
    private final static Map<String, Operation2> stringToEnum = new HashMap<String, Operation2>();
    static {
        for(Operation2 op : Operation2.values()){
            stringToEnum.put(op.toString(), op);
        }
    }
    public static Operation2 fromString(String symbol){
        return stringToEnum.get(symbol);
    }
    abstract double apply(double x, double y);
    public static void main(String[] args){
        double x = Double.parseDouble("2");
        double y = Double.parseDouble("4");
        for(Operation2 op : Operation2.values()){
            System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
        }
        Operation2 op = fromString(" ");
        System.out.println(op);
    }
}

多少个计量寻常薪金和突击报酬的例子:

public enum PayrollDay {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
    private static final int HOURS_PER_SHIFT = 8;
    double pay(double hoursWorked, double payRate){
        double basePay = hoursWorked * payRate;
        double overtimePay;
        switch(this){
            case SATURDAY: case SUNDAY:
                overtimePay = hoursWorked * payRate / 2;
            default:
                overtimePay = hoursWorked <= HOURS_PER_SHIFT ? 0 : (hoursWorked - HOURS_PER_SHIFT) * payRate / 2;
                break;
        }
        return basePay   overtimePay;
    }
}

代码13分精简,但从维护角度来看,它那个危急,同样是因为switch。假使新增加加2个枚举,但忘记在switch语句中增加相应的case,则程序逻辑会出难题。

修改版:

public enum PayrollDay2 {
    MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY(PayType.WEEKDAY), 
    THURSDAY(PayType.WEEKDAY), FRIDAY(PayType.WEEKDAY), 
    SATURDAY(PayType.WEEKEND), SUNDAY(PayType.WEEKEND);
    private final PayType payType;
    private PayrollDay2(PayType payType) {
        this.payType = payType;
    }
    double pay(double hoursWorked, double payRate){
        return payType.pay(hoursWorked, payRate);
    }
    private enum PayType{
        WEEKDAY {
            @Override
            double overtimePay(double hrs, double payRate) {
                return hrs <= HOURS_PER_SHIFT ? 0 : (hrs - HOURS_PER_SHIFT) * payRate / 2;
            }
        },
        WEEKEND {
            @Override
            double overtimePay(double hrs, double payRate) {
                return hrs * payRate / 2;
            }
        };
        abstract double overtimePay(double hrs, double payRate);
        private static final int HOURS_PER_SHIFT = 8;
        double pay(double hoursWorked, double payRate){
            double basePay = hoursWorked * payRate;
            return basePay   overtimePay(hoursWorked, payRate);
        }
    }
}

简单的说,与int比较,枚举类型的优势是明摆着的。枚举易读得多,也愈加安全,作用更是有力。

 

  • Android中新引进的代表枚举的讲明有IntDef和StringDef,这里以IntDef做例子说喜宝(Hipp)(Nutrilon)(Karicare)下.
30,用enum代替int常量

枚举类型是指由壹组固定的常量组成合法值的档期的顺序。

与int常量比较,枚举的优势是醒指标。

  • 枚举要易读的多,也更为安全,功用更有力。
  • 十分的多枚举都没有须求显式的构造器只怕成员,但广大别的枚举则收益于“每一个常量与性子关联”以及“提供行为受这些特性影响的主意”。
  • 唯有极个别枚举收益于将多中表现与单个方法关联。在这种相对少见的状态下,特定于常量的格局要先行于启用自有价值的枚举。
  • 枚举和注解_EJ,枚举和注解。一旦五个枚举常量同不平日候共享同样的作为,则设想攻略枚举。

Java 一.伍发行版本新扩充了多个引用类型家族:枚举类型(Enumerate类)和注释类型(Annotation接口)。

第叁一条:用实例域代替序数

枚举类型有二个ordinal方法,它界定该常量的序数从0开头,不建议采纳那么些办法,因为那不能很好地对枚举举行爱抚,精确应该是运用实例域,举个例子:

public enum Ensemble2 {
    SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5),
    SEXTET(6), SEPTET(7), OCTET(8), DOUBLE_QUARTET(8), 
    NONET(9), DECTET(10);
    private final int nuberOfMusicians;
    Ensemble2(int size){
        this.nuberOfMusicians = size;
    }
    public int numberOfMusicians(){
        return nuberOfMusicians;
    }
}

 

 

3一,用实例域代替序数

具有的枚举都有1个ordinal方法,它回到种种枚举常量在等级次序中的数字的任务。它是统一盘算成用于像EnumSet和EnumMap这种依据枚举的通用数据结构的。

世代不要依据枚举的队列数导出与它有关的值,而是要把它保存在三个实例域中。

第一十条、用enum代替int常量

  1. 枚举类型是指由1组固定的常量组成合法值的类型。取代在此以前的具名的int常量。
    public static final int APPLE_FUJI = 0;

    这种措施叫做int枚举方式,存在重重的欠缺:
    程序特别虚弱,因为int枚举是编译时常量,被编写翻译到利用它们的客户端中。若是与枚举常量关联的int发生了变动,客户端就无法不重新编写翻译,不然,程序作为会变得不明显。(还也许有个变体是String枚举格局)

  2. java的枚举类型是功力非常完备的类,本质上是int值。
    基本主张是:通过国有的静态final域为各个枚举常量导出实例的类。枚举类型是实例受控的,它们是单例的泛型化,精神上是单元素的枚举

    枚举提供了编写翻译时的品种安全,假诺声惠氏(WYETH)(Aptamil)个参数的花色为Apple,就能够保障,被传到该参数上的别样非null的对象引用一定属于四个有效的Apple值之1。试图传递类型错误的值时,会产生编写翻译时不当。
    public enum Apple{FUJI,PIPPIN,GERNNY_SMITH}
    涵盖同名变量的七个枚举类型可以在3个系统淑节平共处,因为每一种门类都有和好的命名空间。

  3. 除去弥补int枚举常量的阙如,枚举类型还同意增加跋扈的不二法门和域(近似于类),并实现自由的接口。它们提供了装有Object方法的高档完结,完成了Comparable和塞里alizable接口。大家为何要将艺术只怕域加入到枚举类型中?将数据与它的常量关联起来。可以用别样方便的点子来增加枚举类型。

     /**
      * Created by laneruan on 2017/7/10.
      * 一个枚举类型的例子
      * 为了将数据与枚举常量关联起来,得声明实例域,并编写一个带有数据并将数据保存在域中的构造器。
      */
     public class EnumPlanet {
         public enum Planet{
             MERCURY(3.302e 23,2.439e6),
             VENUS(4.8693 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);
             private final double mass;
             private final double radius;
             private final double surfaceGravity;
             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 = Double.parseDouble(args[0]);
             double mass = earthWeight/Planet.EARTH.surfaceGravity();
             for (Planet p : Planet.values()){
                 System.out.println("Weight on "   p  " is " p.surfaceWeight(mass));
             }
         }
     }
    

    与枚举常量关联的某些行为,恐怕只须要用在概念了枚举的类照旧包中,这种表现最棒被达成成私有的依然包级私有的格局。
    如若一个枚举拥有广泛适用性,它就应该改成一个顶层类。若是它是被用在3个特定的顶层类中,它就应当改成该顶层类的贰个成员类。

  4. 一定于常量的不贰秘技实现:将不一致的行为与各类枚举常量关联起来

     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;
             }
         };
         abstract double apply(double x,double y),
     }
    
  5. 怎样时候理应选择枚举类型?
    每当必要壹组固定常量的时候。包罗:天然的枚举类型;在编写翻译的时候就知晓其有着大概值的聚众。

  6. 总计:与int常量比较,枚举类型的优势一清二楚:易读,特别安全。作用越来越强硬。多数枚举都无需显式的构造器或然成员,但多数别样枚举类型则得益于“各个常量与品质的涉嫌”以及“提供行为受那天性格影响的不2诀要”。


第1贰条:用EnumSet代替位域

位域表示法允许选拔位操作,有效地实施先联合和混合那样的联谊操作。可是位域有着int枚举常亮的富有缺点,乃至更加多。当位域一数字格局打字与印刷时,翻译位域比翻译轻松的int枚举常量要困难得多。乃至,要遍历位域表示的有着因素都未有很轻易的法子。

public class Text {
    public static final int STYLE_BOLD                   = 1 << 0;    //1
    public static final int STYLE_ITALIC                  = 1 << 1;    //2
    public static final int STYLE_UNDERLINE         = 1 << 3;    //4
    public static final int STYLE_STRIKETHROUGH = 1 << 3;    //8

    public void applyStyles(int styles){}
}

java.util 包提供了EnumSet类来有效地表示从单个枚举类型中提取的多少个值的两个汇集。这一个类落成Set接口,提供了增加的意义,类型安全性,以及能够从其余其它Set实现中赢得的互用性。可是在里头具体的落到实处上,各样EnumSet内容都意味着为位矢量。就算底层的枚举类型有陆拾个恐怕更加少的要素——大多数这么。整个EnumSet就用单个long来表示,因而它的品质比的上位域的天性。批管理,如removeAll和retainAll,都以应用位算法来落到实处的。就如手工业代替位域实现得那样。不过足以免止手工业操作时便于并发的荒唐以及不太优雅的代码,因为EnumSet替你做到了那项劳苦的做事。`

//EnumSet - a modern replacement for bit fields
public class Text2 {
  public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH };

  //Any Set could be passed in, but EnumSet is clearly best
  public void applyStyles(Set<Style> styles) { 
      System.out.println(styles);
  }

  public void test() {
      applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
  }
}

简单来讲,正因为枚举类型要用在集结Set中,所以并未有理由用位域来代表它。

 

public class Colors {
    @IntDef({RED, GREEN, YELLOW})
    //声明必要的int常量,使用@IntDef修饰LightColors,参数设置为待枚举的集合
    @Retention(RetentionPolicy.SOURCE)
    //使用@Retention(RetentionPolicy.SOURCE)指定注解仅存在与源码中,不加入到class文件中
    public @interface LightColors{}
    //声明一个注解为LightColors
    public static final int RED = 0;
    public static final int GREEN = 1;
    public static final int YELLOW = 2;
}
//用法
private void setColor(@Colors.LightColors int color) {
        Log.d("MainActivity", "setColor color="   color);
}
//调用的该方法的时候
setColor(Colors.GREEN);
3二,用EnumSet代替位域

这种表示法让你用OCR-V位运算将多少个常量合并到贰个成团中,称作位域。

举例说,有个别方法通过参数获取类的2个常量。某些像从Map中通过key获取值。

java.util包提供了EnumSet类来有效地代表从单个枚举类型中领到八个值的多少个集聚。

第二十一条、用实例域代替序数

多数枚举天生就与八个独门的int值相关联,全体的枚举都有三个ordinal方法,它回到各个枚举常量在类型中的数字地点。可以试着从序数中获取关联的int值。最棒制止使用ordinal方法。

千古不要根据枚举的序数导出与它想关联的值,而是要将它保存在3个实例域中:

    public enum Ensemble{
        SOLO(1),DUET(2),TRIO(3),QUARTET(4),QUINTET(5),
        SETET(6),SEPET(7),OCTET(8),NONET(9),DECTET(10);
        private final int numberOfMusicians;
        Ensemble(int size){
            this.numberOfMusicians = size;
        }
        public int numberOfMusicians(){return numberOfMusicians;}
    //   public int numberOfMusicians(){return ordinal() 1;}
    }

本文由bwin必赢发布,转载请注明来源

关键词: Java 必赢游戏 Android笔记 Effective Ja