> Java > java지도 시간 > Java 열거형 사용에 대한 자세한 설명

Java 열거형 사용에 대한 자세한 설명

黄舟
풀어 주다: 2017-09-09 11:23:18
원래의
1969명이 탐색했습니다.

이 글은 주로 Java 열거형 사용에 대한 자세한 설명을 소개합니다. 이 글을 통해 열거형 사용법을 익힐 수 있기를 바랍니다. 도움이 필요한 친구는

Java 열거형 사용에 대한 자세한 설명을 참조하세요.

머리말: 코드의 플래그와 상태는 열거형으로 대체되어야 합니다.

많은 사람들은 열거형이 실제 개발에서 거의 사용되지 않거나 심지어 사용되지 않는다고 말합니다. 왜냐하면 그들의 코드는 종종 다음과 같기 때문입니다:


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行代码 
}
로그인 후 복사

그리고 그들은 이 클래스를 다음과 같이 사용합니다:


hero.setStatus(Contant.STATUS_ATTACKING);
로그인 후 복사

그러면 그들은 "실제 개발 경험이 거의 없습니다. 열거형을 사용하세요"라고 말합니다.

물론 열거형 클래스인 Enum이 거의 사용되지 않는다는 의미입니다.

그러나 제가 말씀드리고 싶은 것은 위의 코드는 모두 Enum을 사용하여 구현되어야 한다는 것입니다.

왜요?

그들의 코드는 전적으로 팀원에 대한 신뢰를 기반으로 하기 때문입니다. 이상한 팀원이 와서 이렇게 한다고 가정해 보세요.


hero.setStatus(666);
로그인 후 복사

화면 속 영웅에게 어떤 일이 일어날 것이라고 생각하시나요?

요컨대, 실제 프로그래밍에서 이런 코드를 자주 사용한다면 이제 Enum을 배울 차례입니다.

열거형에 대한 예비 연구 열거형을 사용하는 이유

행성, 요일과 같은 "자연 열거형"은 물론 csdn 탭 레이블과 같이 우리가 디자인한 열거형까지 삶의 모든 곳에 열거형이 있습니다. , 메뉴 등

Java 코드에서 열거형을 표현하는 방법에는 일반적으로 두 가지가 있습니다. 하나는 int 열거형이지만 Enum 열거형은 물론 Java에서 제공하는 실제 열거형이라는 것을 모두 알고 있습니다.

그렇다면 왜 Enum 열거형을 사용할까요? 먼저 Java 1.5 이전에는 열거형 유형이 없었을 때 열거형을 어떻게 표현했는지 살펴보겠습니다.

8개의 행성을 예로 들어보겠습니다. 각 행성은 int 값에 해당합니다. 아마 이렇게 쓸 것입니다.


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; 
}
로그인 후 복사

이를 int 열거 모드라고 합니다. , 무슨 일이 있어도 이 접근 방식은 유형 안전성과 유용성이 좋지 않습니다.
변수 planet이 행성을 나타내는 경우 사용자는 이 값을 우리의 열거 값에 없는 값(예: planet = 9)에 할당할 수 있습니다. 더욱이 이것이 어떤 행성인지는 오직 신만이 알 수 있으므로 우리가 이를 계산하기는 어렵습니다. .. 행성이 몇 개나 있나요?

이제 우리는 열거형을 사용하여 행성을 만듭니다.


public enum Planet { 
  MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE; 
}
로그인 후 복사

위는 가장 간단한 열거입니다. Planet 1.0이라고 부르겠습니다. 이 버전의 행성 열거에서는 함수를 구현했습니다. 즉, Planet 유형의 모든 변수는 컴파일러에 의해 보장될 수 있습니다. 매개 변수에 전달된 null이 아닌 개체는 이 8개 행성 중 하나에 속해야 합니다.

그리고 Planet을 업그레이드하면 열거형에 어떤 메서드든 추가할 수 있습니다. 소개 책에 있는 코드는 누구나 열거형 생성자, 열거형 탐색 및 기타 지식 포인트를 경험할 수 있습니다.


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)); 
  } 
}
로그인 후 복사

Run WeightTable, 인쇄 결과는 다음과 같습니다.


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
로그인 후 복사

이 작은 프로그램에서는 열거형 A를 반환하는 열거형의 value() 메서드를 사용합니다. 열거형 변수 모음, 매우 실용적입니다.

고급 열거형 계산기 연산자 열거형 클래스

이전 섹션의 예에서는 열거형 클래스의 공개 메서드를 사용했습니다. 이 섹션에서는 계산기 연산자 열거형 클래스를 예로 들어 다양한 연산을 구현하는 방법을 살펴보겠습니다. 각 열거 객체에 대해.


우선 메소드를 쉽게 생각할 수 있는데, 공개 메소드에서는 스위치를 사용해 열거형을 결정한 뒤, 코드는 다음과 같습니다.


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); 
  } 
}
로그인 후 복사

이 코드는 정말 그렇습니다. 필수 사항을 구현하지만 두 가지 단점이 있습니다.


먼저 예외를 발생시키거나 스위치에 기본값을 추가해야 합니다. 그렇지 않으면 컴파일할 수 없습니다. 하지만 분명히 프로그램 분기에서는 예외나 기본값을 입력하지 않습니다.


두 번째로, 이 코드는 매우 취약합니다. 새 작업 유형을 추가했지만 스위치에 해당 처리 논리를 추가하는 것을 잊어버리면 새 작업을 수행할 때 문제가 발생합니다.


다행히 Java 열거형은 상수별 메서드 구현이라는 기능을 제공합니다.


열거형에서 추상 메서드만 선언한 다음 각 열거형 상수에서 이 메서드를 재정의하면 됩니다. 구현은 다음과 같습니다.


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); 
}
로그인 후 복사

이렇게 하면 새로운 작업이 발생하지 않습니다. 추가됨 기호 뒤에 해당 처리 논리를 추가하는 것을 잊어버린 경우 컴파일러는 적용 메서드를 재정의해야 한다는 메시지를 표시합니다.


그러나 이 상수 특정 메소드 구현에는 단점이 있습니다. 즉, 열거형 상수 간에 코드를 공유하기가 어렵습니다.


주를 열거해 봅시다

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


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是两个为枚举而设计的集合,在实际开发中,用到枚举集合时,请优先考虑这两个。

위 내용은 Java 열거형 사용에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿