Maison  >  Article  >  Java  >  Explication détaillée de l'utilisation des énumérations Java

Explication détaillée de l'utilisation des énumérations Java

黄舟
黄舟original
2017-09-09 11:23:181951parcourir

Cet article présente principalement des informations pertinentes sur l'utilisation des énumérations Java. J'espère que grâce à cet article, vous pourrez maîtriser l'utilisation des énumérations. Les amis dans le besoin pourront se référer à

Explication détaillée des énumérations Java. comment utiliser

Préface Le drapeau et le statut dans votre code doivent être remplacés par des énumérations

Beaucoup de gens disent que l'énumération Il est rarement utilisé dans développement réel, voire pas du tout utilisé. Parce que leur code ressemble souvent à ceci :


public class Constant { 
  /* 
   * 以下几个变量表示英雄的状态 
   */ 
  public final static int STATUS_WALKING = 0;//走  
  public final static int STATUS_RUNNINGING = 1;//跑 
  public final static int STATUS_ATTACKING = 2;//攻击  
  public final static int STATUS_DEFENDING = 3;//防御  
  public final static int STATUS_DEAD = 4;//挂了  
   
  /* 
   * 以下几个变量表示英雄的等级 
   */ 
  //此处略去N行代码 
}

Ensuite, ils utilisent cette classe comme ceci :


hero.setStatus(Contant.STATUS_ATTACKING);

Eh bien, ils ont dit : "J'utilise rarement les énumérations dans le développement réel"

Bien sûr, ils veulent dire très La classe Enum est rarement utilisée.

Cependant, ce que je veux dire, c'est que tous les codes ci-dessus doivent être implémentés à l'aide d'Enum.

Pourquoi ?

Parce que leur code est entièrement basé sur la confiance dans les coéquipiers, supposons qu'un étrange coéquipier vienne et fasse ceci :


hero.setStatus(666);

Selon vous, que va-t-il arriver aux héros à l’écran ?

En bref, si vous utilisez souvent un tel code dans la programmation réelle, il est temps d'apprendre Enum.

Une étude préliminaire sur les énumérations Pourquoi utiliser les types d'énumération

Il existe des énumérations partout dans la vie, y compris les « énumérations naturelles », comme les planètes et les semaines Le nombre de jours inclut également les énumérations que nous avons conçues, telles que les étiquettes des onglets csdn, les menus, etc.

Il existe généralement deux façons d'exprimer les énumérations dans le code Java. L'une est l'énumération int, mais l'énumération Enum. Bien sûr, nous savons tous que l'énumération Enum est fournie par Java True.

Alors, pourquoi utilisons-nous le type d'énumération Enum ? Voyons d'abord comment nous représentions les énumérations avant Java 1.5, lorsqu'il n'existait aucun type d'énumération.

En prenant les huit planètes comme exemple, chaque planète correspond à une valeur int On l'écrirait probablement ainsi


public class PlanetWithoutEnum { 
  public static final int PLANET_MERCURY = 0; 
  public static final int PLANET_VENUS = 1; 
  public static final int PLANET_EARTH = 2; 
  public static final int PLANET_MARS = 3; 
  public static final int PLANET_JUPITER = 4; 
  public static final int PLANET_SATURN = 5; 
  public static final int PLANET_URANUS = 6; 
  public static final int PLANET_NEPTUNE = 7; 
}
.

C'est ce qu'on appelle le mode d'énumération int. Bien sûr, vous pouvez également utiliser le mode d'énumération String. Quelle que soit la méthode utilisée, cette approche est très mauvaise en termes de sécurité de type et de convivialité.
Si la variable planète représente une planète, l'utilisateur peut attribuer à cette valeur une valeur qui n'est pas dans notre valeur d'énumération, comme planète = 9. Dieu seul sait de quelle planète il s'agit d'ailleurs, il nous est difficile de le faire ; calculer Sans savoir combien il y a de planètes, il nous serait difficile de parcourir les planètes et ainsi de suite.

Maintenant, nous utilisons des énumérations pour créer nos planètes.


public enum Planet { 
  MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE; 
}

L'énumération ci-dessus est la plus simple. Appelons-la Planète 1.0. Pour cette version de l'énumération des planètes, nous avons implémenté une fonction, qui est Pour. n'importe quelle variable de type Planète, le compilateur peut garantir que tout objet non nul passé en paramètre doit appartenir à l'une de ces huit planètes.

Ensuite, nous mettons à niveau Planet. Java nous permet d'ajouter n'importe quelle méthode au type d'énumération. Voici une introduction au code dans le livre. Expérimentons le constructeur, la méthode publique et l'énumération de l'énumération. Donnez des points de connaissance tels que la traversée.


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; // In kilograms 
  private final double radius; // In meters 
  private final double surfaceGravity; // In m / s^2 
 
  // Universal gravitational constant in m^3 / kg s^2 
  private static final double G = 6.67300E-11; 
 
  // Constructor 
  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; // F = ma 
  } 
}


//注:这里对书中的代码做了微调 
public class WeightTable { 
  public static void main(String[] args) { 
    printfWeightOnAllPlanets(8d); 
  } 
 
  public static void printfWeightOnAllPlanets(double earthWeight) { 
    double mass = earthWeight / Planet.EARTH.surfaceGravity(); 
    for (Planet p : Planet.values()) 
      System.out.printf("Weight on %s is %f%n", p, p.surfaceWeight(mass)); 
  } 
}

Exécutez WeightTable, le résultat de l'impression est le suivant :


Weight on MERCURY is 3.023254
Weight on VENUS is 7.240408
Weight on EARTH is 8.000000
Weight on MARS is 3.036832
Weight on JUPITER is 20.237436
Weight on SATURN is 8.524113
Weight on URANUS is 7.238844
Weight on NEPTUNE is 9.090108

Dans ce petit programme, nous utilisons la méthode values() de l'énumération. Cette méthode renvoie une collection de variables d'énumération dans le type énumération, ce qui est très pratique.

Classe d'énumération d'opérateur de calculatrice avancée d'énumération

Dans l'exemple de la section précédente, nous avons utilisé les méthodes publiques de la classe d'énumération. Dans cette section, nous utilisons l'opération de calculatrice Prendre le. Classe d'énumération d'opérations comme exemple pour voir comment effectuer différentes opérations pour chaque objet d'énumération

.

Tout d'abord, on peut facilement penser à une méthode. Dans la méthode publique, utilisez switch pour déterminer le type d'énumération, puis effectuez différentes opérations. Le code est le suivant :


public enum OperationUseSwitch { 
  PLUS, MINUS, TIMES, pIDE; 
 
  double apply(double x, double y) { 
    switch (this) { 
      case PLUS: 
        return x + y; 
      case MINUS: 
        return x + y; 
      case TIMES: 
        return x + y; 
      case pIDE: 
        return x + y; 
    } 
    // 如果this不属于上面四种操作符,抛出异常 
    throw new AssertionError("Unknown operation: " + this); 
  } 
}

Ce code répond certes à nos besoins, mais il présente deux inconvénients.

Tout d'abord, nous devons lever une exception à la fin ou ajouter une valeur par défaut dans le commutateur, sinon la compilation ne passera pas. Mais évidemment, la branche du programme n'entrera pas dans l'exception ou. défaut.

Deuxièmement, ce code est très fragile. Si nous ajoutons un nouveau type d'opération mais oublions d'ajouter la logique de traitement correspondante dans le commutateur, des problèmes surviendront lors de l'exécution de nouvelles opérations.

Heureusement, les énumérations Java fournissent une fonctionnalité appelée implémentation de méthode spécifique à une constante.

Il suffit de déclarer une méthode abstraite dans le type d'énumération, puis de remplacer cette méthode dans chaque constante d'énumération. L'implémentation est la suivante :


public enum Operation { 
  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; 
    } 
  }, 
  pIDE { 
    double apply(double x, double y) { 
      return x / y; 
    } 
  }; 
 
  abstract double apply(double x, double y); 
}

De cette façon, nous n'oublierons jamais d'ajouter la logique de traitement correspondante après avoir ajouté un nouvel opérateur, car le compilateur nous demandera que nous devons remplacer la méthode apply.

Cependant, cette implémentation de méthode spécifique aux constantes présente un inconvénient, c'est-à-dire qu'il vous est difficile de partager du code entre les constantes d'énumération.

Prenons le décompte de la semaine

如果还是使用 特定于常量的方法实现,写出来的代码可能就是这样的:


public enum DayUseAbstractMethod { 
  MONDAY { 
    @Override 
    void apply() { 
      dealWithWeekDays();//伪代码 
    } 
  }, 
  TUESDAY { 
    @Override 
    void apply() { 
      dealWithWeekDays();//伪代码 
    } 
  }, 
  WEDNESDAY { 
    @Override 
    void apply() { 
      dealWithWeekDays();//伪代码 
    } 
  }, 
  THURSDAY { 
    @Override 
    void apply() { 
      dealWithWeekDays();//伪代码 
    } 
  }, 
  FRIDAY { 
    @Override 
    void apply() { 
      dealWithWeekDays();//伪代码 
    } 
  }, 
  SATURDAY { 
    @Override 
    void apply() { 
      dealWithWeekEnds();//伪代码 
    } 
  }, 
  SUNDAY { 
    @Override 
    void apply() { 
      dealWithWeekEnds();//伪代码 
    } 
  }; 
 
  abstract void apply(); 
}

很明显,我们这段代码里面有相当多的重复代码。

那么要怎么优化呢,我们不妨这样想,星期一星期二等等是一种枚举,那么工作日和休息日,难道不也是一种枚举吗,我们能不能给Day的构造函数传入一个工作日休息日的DayType枚举呢?这也就是书中给出的一种叫策略枚举 的方法,代码如下:


public enum Day { 
  MONDAY(DayType.WEEKDAY), TUESDAY(DayType.WEEKDAY), WEDNESDAY( 
      DayType.WEEKDAY), THURSDAY(DayType.WEEKDAY), FRIDAY(DayType.WEEKDAY), SATURDAY( 
      DayType.WEEKDAY), SUNDAY(DayType.WEEKDAY); 
  private final DayType dayType; 
 
  Day(DayType daytype) { 
    this.dayType = daytype; 
  } 
 
  void apply() { 
    dayType.apply(); 
  } 
 
  private enum DayType { 
    WEEKDAY { 
      @Override 
      void apply() { 
        System.out.println("hi, weekday"); 
      } 
    }, 
    WEEKEND { 
      @Override 
      void apply() { 
        System.out.println("hi, weekend"); 
      } 
    }; 
    abstract void apply(); 
  } 
}

通过策略枚举的方式,我们把Day的处理逻辑委托给了DayType,个中奥妙,读者可以细细体会。

枚举集合   EnumSet的使用

EnumSet提供了非常方便的方法来创建枚举集合,下面这段代码,感受一下


public class Text { 
  public enum Style { 
    BOLD, ITALIC, UNDERLINE, STRIKETHROUGH 
  } 
 
  // Any Set could be passed in, but EnumSet is clearly best 
  public void applyStyles(Set<Style> styles) { 
    // Body goes here 
    for(Style style : styles){ 
      System.out.println(style); 
    } 
  } 
 
  // Sample use 
  public static void main(String[] args) { 
    Text text = new Text(); 
    text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC)); 
  } 
}

这个例子里,我们使用了EnumSet.of方法,轻松创建了枚举集合。

枚举Map   EnumMap的使用

假设对于香草(Herb),有一个枚举属性Type(一年生、多年生、两年生)

Herb:


public class Herb { 
  public enum Type { ANNUAL, PERENNIAL, BIENNIAL } 
 
  private final String name; 
  private final Type type; 
   
  Herb(String name, Type type) { 
    this.name = name; 
    this.type = type; 
  } 
 
  @Override public String toString() { 
    return name; 
  } 
}

现在,假设我们有一个Herb数组,我们需要对这个Herb数组按照Type进行分类存放。

所以接下来,我们需要创建一个Map,value肯定是Herb的集合了,那么用什么作为key呢?

有的人会使用枚举类型的ordinal()方法,这个函数返回int类型,表示枚举遍历在枚举类里的位置,这样做,缺点很明显,由于你的key的类型是int,不能保证传入的int一定能和枚举类里的变量对应上。

所以,在key的选择上,毫无疑问,只能使用枚举类型,也即Herb.Type。

最后还有一个问题,要使用什么Map? Java为枚举类型专门提供了一种Map,叫EnumMap,相比较与其他Map,这种Map在处理枚举类型上更快,有兴趣的同学可以研究一下这个map的内部实现。

下面让我们看看怎么使用EnumMap:


public static void main(String[] args) { 
  Herb[] garden = { new Herb("Basil", Type.ANNUAL), 
      new Herb("Carroway", Type.BIENNIAL), 
      new Herb("Dill", Type.ANNUAL), 
      new Herb("Lavendar", Type.PERENNIAL), 
      new Herb("Parsley", Type.BIENNIAL), 
      new Herb("Rosemary", Type.PERENNIAL) }; 
 
  // Using an EnumMap to associate data with an enum - Page 162 
  Map<Herb.Type, Set<Herb>> herbsByType = new EnumMap<Herb.Type, Set<Herb>>( 
      Herb.Type.class); 
  for (Herb.Type t : Herb.Type.values()) 
    herbsByType.put(t, new HashSet<Herb>()); 
  for (Herb h : garden) 
    herbsByType.get(h.type).add(h); 
  System.out.println(herbsByType); 
 
}

总结

和int枚举相比,Enum枚举的在类型安全和使用便利上的优势是不言而喻的。
Enum为枚举提供了丰富的功能,如文章中提到的特定于常量的方法实现和策略枚举。
EnumSet和EnumMap是两个为枚举而设计的集合,在实际开发中,用到枚举集合时,请优先考虑这两个。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn