💁♀️ Enum이란,
컴퓨터 프로그래밍에서 Enumerated Type(열거형 타입)을 줄여 보통 Enum이라고 지칭하며 요소, 멤버라 불리는 명명된 값의 집합을 이루는 자료형
/* 상수필드 : 이 값에 대한 의미를 부여하기 위함 */
public static final int JAVA = 0;
public static final int ORACLE = 1;
public static final int JDBC = 2;
public static final int HTML = 0;
public static final int CSS = 1;
public static final int JAVASCRIPT = 2;
public static void main(String[] args) {
/* 정수 열거 패턴(enum이 생기기 전의 패턴)의 문제점 */
/* 1. 정수 값 만을 저장하고 있는 필드일 뿐임 */
int subject1 = Subjects.JAVA; // 0
int subject2 = Subjects.HTML; // 0
/* 둘 다 상수 0을 가지기 때문에 구분이 불가능 */
if(subject1 == subject2) {
System.out.println("두 과목은 같은 과목 ^^");
}
/* 2. 변수명 충돌 방지를 위해 접두어를 써서 구분해야함
* BACKEND_JAVASCRIPT = 0;
* FRONTEND_JAVASCRIPT = 0;
* */
/* 3. 문자열로 출력하기 까다로움(따로 가공처리가 필요) */
int num = 0;
String subjectText = "";
switch(num) {
case Subjects.JAVA : subjectText = "JAVA"; break;
case Subjects.ORACLE : subjectText = "ORACLE"; break;
case Subjects.JDBC : subjectText = "JDBC"; break;
}
System.out.println("subjectText : " + subjectText);
/* 4. 같은 그룹에 속한 상수들을 순회(반복문 사용) 할 수 없고 전체 상수의 개수 확인도 불가능 */
/* 5. 타입 안정성을 보장할 수 없음 */
printSubject(Subjects.ORACLE);
printSubject(1); // Subjects 뿐만 아니라 int 타입으로도 인자 전달 가능
}
public static void printSubject(int subjectNumber) {
String subjectText = "";
switch(subjectNumber) {
case Subjects.JAVA : subjectText = "JAVA"; break;
case Subjects.ORACLE : subjectText = "ORACLE"; break;
case Subjects.JDBC : subjectText = "JDBC"; break;
}
System.out.println("subjectText : " + subjectText);
}
/* 작성한 순서대로 0부터 값이 자동으로 부여됨 */
JAVA, // 0
ORACLE, // 1
JDBC, // 2
HTML, // 3
CSS, // 4
JAVASCRIPT // 5
==
toSting()
values()
public static void main(String[] args) {
/* 1. 열거 타입(Enum)으로 선언 된 인스턴스는 싱글톤으로 관리되며 인스턴스가 한 개임을 보장 */
Subjects subject1 = Subjects.JAVA;
Subjects subject2 = Subjects.HTML;
if(subject1 == subject2) {
System.out.println("두 과목은 같은 과목이에요!");
} else {
System.out.println("두 과목은 다른 과목이에요!"); // 출력
}
/* 단일 인스턴스임을 보장하기에 == 비교가 가능 */
System.out.println(subject1 == Subjects.JAVA); // true
/* 2. 변수명 충돌 방지를 위해 접두사를 쓰지 않아도 Enum 타입별로 네임 스페이스를 가짐
* 동일한 이름의 상수가 필요하면 Enum 타입별로 네임스페이스를 다르게 하면 됨
* public enum Backend { JAVA, ORECLE, JDBC, JAVASCRIPT }
* public enum Frontend { HTML, CSS, JAVASCRIPT }
* */
/* 3. toSting()을 이용하여 문자열로 변경하기 쉬움(따로 switch문으로 가공 필요X) */
System.out.println(Subjects.JAVA.toString()); // JAVA
/* 4. values()를 이용하여 상수 값 배열을 반환하고 이를 통해 연속 처리 가능 */
Subjects[] subjects = Subjects.values(); // Subjects의 모든 과목 목록이 순회되며 출력
for(Subjects s : subjects) {
System.out.println(s);
}
/* 5. 타입 안정성을 보장 */
printSubject(Subjects.HTML);
// printSubject(3); // 정수 열거 패턴에서 확인한 것 처럼 int 타입으로 전달 불가 (타입 안정성 보장)
}
public static void printSubject(Subjects subject) { // int가 아닌 Subjects라는 Enum 타입으로 동작
System.out.println(subject.toString());
}
name()
toLowerCase()
/* Enum은 상수 하나 하나가 인스턴스화 될 수 있음 */
GUEST,
CONSUMER,
PRODUCER,
ADMIN; // 생성자 작성 시 열거형 상수 선언 마지막에 세미콜론 붙여야함
/* 기본 생성자를 가질 수 있음
* default와 private 접근 제한 사용 가능하지만 외부에서 호출은 불가능 (묵시적으로 private)
* enum 타입은 고정된 상수들의 집합으로 런타임이 아닌 컴파일 시에 모든 값이 결정되어 있어야 함
* 따라서 다른 클래스에서 enum 타입에 접근해 동적으로 생성자를 이용해 어떤 값을 전달 해줄 수 없기 때문 */
UserRole1() {}
/* 필요하다면 메소드도 만들 수 있음 */
public String getNameToLowerCase() {
return this.name().toLowerCase();
}
/* 각각의 요소들이 특정한 값을 가지게 할 수도 있음 */
GUEST("게스트"), // String 값으로 생성자를 호출하기 때문에 생성자를 반드시 생성해야함
CONSUMER("구매자"),
PRODUCER("판매자"),
ADMIN("관리자");
private final String description; // description 필드 생성
/* 이런 경우에는 매개변수가 있는 생성자가 반드시 필요
* enum 상수의 괄호 안에 넣은 값이 해당 생성자 쪽으로 전달 되며 enum 인스턴스가 생성됨
* 생성 된 인스턴스는 '싱글톤 객체' */
UserRole2(String description) {
System.out.println("description : " + description); // 언제 호출되는지 확인하기 위한 출력문
this.description = description; // 받은 String값을 이 생성자가 호출될 때 마다 필드에 초기화
}
/* 요소들이 가지는 기본 네임과 정수 값 외의 값을 !외부에서 사용하려고 할 때! 필드로 작성한 값을 반환하도록
* 메소드를 작성할 수 있음 */
public String getDescription() {
return this.description;
}
EnumSet
ordinal()
getDescription()
iterator()
hasNext()
next()
allOf()
of()
UserRole1 admin = UserRole1.ADMIN;
System.out.println(admin);
System.out.println(admin.getNameToLowerCase());
/* 최초 enum 타입을 사용할 시 생성자가 호출 됨. 하지만 이것이 동적으로 생성되는 것을 의미하는 것은 아님 */
UserRole2 consumer = UserRole2.CONSUMER;
System.out.println(consumer.ordinal() + " " + consumer.name() + " " + consumer.getDescription()); /* ordinal() : 가지고 있는 숫자 반환 */
/* description : 게스트
description : 구매자
description : 판매자
description : 관리자
1 CONSUMER 구매자 // 바로 위의 출력문을 통해 출력된 결과
*/
/* 최초 사용 시에만 열거 타입의 인스턴스를 생성하고 이후에는 생성자를 호출하지 않음 (두 번째 호출 시에는 생성자 호출 X) */
UserRole2 consumer2 = UserRole2.CONSUMER;
/* 인스턴스는 싱글톤으로 관리되기 때문에 동일 비교 연산으로 비교 가능 */
System.out.println(consumer == consumer2); // 주소값이 같으므로 true 반환
System.out.println("==========================================================================");
/* EnumSet을 활용하여 여러 열거형 타입들을 set(순서 X, 중복 저장 X)으로 취급 가능 */
EnumSet<UserRole2> roles = EnumSet.allOf(UserRole2.class); // allOf() : Enum으로 선언 된 모든 것을 가져옴
/* Iterator로 set 형태인 roles의 순서를 배치 후 순서대로 값 가져옴 */
Iterator<UserRole2> iter = roles.iterator();
while(iter.hasNext()) {
System.out.println(iter.next().name());
}
System.out.println("==========================================================================");
/* 특정 상수만 골라서 set에 추가 가능 */
EnumSet<UserRole2> users = EnumSet.of(UserRole2.CONSUMER, UserRole2.PRODUCER); // of() : 특정 상수만 고를 수 있음
Iterator<UserRole2> userIter = users.iterator();
while(userIter.hasNext()) {
System.out.println(userIter.next().name());
}
System.out.println("==========================================================================");
/* 특정 상수만 골라서 제거하고 set에 추가 가능 */
EnumSet<UserRole2> exceptGuest = EnumSet.complementOf(EnumSet.of(UserRole2.GUEST)); // complementOf() : 특정 상수만 제외한 나머지만 고를 수 있음
Iterator<UserRole2> exceptGuestIter = exceptGuest.iterator();
while(exceptGuestIter.hasNext()) {
System.out.println(exceptGuestIter.next().name());
}