[영상후기] [자바의 정석 - 기초편] ch12-17~20 열거형 && ch12-21,22 열거형멤버추가하기

박철현·2024년 2월 19일
0

영상후기

목록 보기
145/160

movie

열거형

  • 관련된 상수들을 같이 묶어 놓은것
class Card {
	// 카드 무늬
	static final int CLOVER = 0;
    static final int HEART = 1;
    static final int DIAMOND = 2;
    static final int SPADE = 3;
    // 카드 숫자
    static final int TWO = 0;
    static final int THREE = 1;
    static final int FOUR = 2;
    
    final int kind;
    final int num;
 }
  • 위 처럼 정의하기엔 너무 많음

  • 간단하게 정의할 수 있는 것이 열거형

    • 값 & 타입 모두 체크하는 장점이 있음

      class Card { 
         // 상수가 자동으로 0부터 매겨짐
         // {0, 1, 2, 3}
      	enum Kind   {CLOVER, HEART, DIAMOND, SPADE}
         // {0, 1, 2}
         enum Value { TWO, THREE, FOUR}
         
         final Kind kind;  // 타입은 int가 아닌 kind임을 유의
         final Value value;
      }
      
       // C언어에서는 값만 체크하기에 같다고 나옴
       // 하지만 Java에서는 타입에 안전한 열거형 제공
       // - 값 & 타입 체크
      
       // C언어 : 값만 체크 가능해서 true지만 false여야 의미상 맞음 (값이 같기에 true)
       // Java : 컴파일 에러, 값은 같지만 타입이 달라서 비교 불가
       if(Card.CLOVER == CARD.TWO) 
       
       if(Card.kind.CLOVER == Card.Value.TWO) { // 컴파일 에러, 타입이 달라서 비교 불가

열거형 정의와 사용

  • 열거형을 정의하는 방법
enum 열거형이름 {상수명1, 상수명2, ...}
// 0, 1, 2, 3
enum Direction { EAST, SOUTH, WEST, NORTH}
  • 열거형 타입의 변수를 선언하고 사용하는 방법
class Unit {
	int x, y;  // 유닛의 위치
    // 열거형 인스턴스 변수 선언
    // Direction 외의 값을 넣을 수 없음
    Direction dir; 
    
    void init() {
    	dir = Direction.EAST;  // 유닛의 방향 EAST 초기화
    }
}
  • 열거형 상수 비교에 ==와 compareTo() 사용가능
// true
if(dir == Direction.EAST) {
	x++;
}

// 에러, 열거형 상수 비교연산자 사용불가
else if (dir > Direction.WEST) { 
}
else if (dir.compareTo(Direction.WEST) > 0 ) { // compareTo()는 가능
// compareTo() : 왼쪽이 크면 양수, 오른쪽이 크면 음수, 같으면 0
}

열거형의 조상 - java.lang.Enum

  • 모든 열거형은 Enum의 자손이며 아래 메서드를 상속받는다.
    • 모든 열거형은 Enum의 메서드를 사용할 수 있다.
메소드설명
Class<E> getDeclaringClass()열거형의 Class객체를 반환
String name()열거형 상수의 이름을 문자열로 반환
int ordinal()열거형 상수가 정의된 순서를 반환(0부터 시작)
T valueOf(Class<T> enumType, String name)지정된 열거형에서 name과 일치하는 열거형 상수를 반환
  • values(), valueOf()는 컴파일러가 자동으로 추가

    • 컴파일러가 자동으로 넣어주기 때문에 모든 열거형 상수에서 사용할 수 있다.
      • static E[] values()
        • 열거형 상수가 가지고 있는 모든 상수를 배열로 반환
      • static E valueOf(String name)
        • 열거형 상수 이름을 주면 열거형 상수 반환
    Direction[] dArr = Direction.values();
    
    for(Direction d : dArr) 
    	System.out.printf("%s = %d%n", d.name(), d.ordinal());
      
    Direction d = Direction.valueOf("WEST"); // 열거형 상수 이름
    // Direction.WEST 와 같은 의미

예제

enum Direction { EAST, SOUTH, WEST, NORTH}

public class Main {
	public static void main(String[] args) {
    	Direction d1 = Direction.EAST; // 열거형 타입.상수이름
        Direction d2 = Direction.valueOf("WEST"); // == Direction.WEST
        Direction d3 = Enum.valueOf(Direction.class, "EAST"); // Direction.EAST
        
        System.out.println("d1="+d1);  // d1=EAST
        System.out.println("d2="+d2);	// d2=WEST
        System.out.println("d3="+d3);	// d3=EAST
        
        System.out.println("d1==d2 ? " + (d1==d2)); // d1==d2 ? false
        System.out.println("d1==d3 ? " + (d1==d3)); // d1==d3 ? true
        System.out.println("d1.equals(d3) ? " + d1.equals(d3)); // d1.equals(d3) ? true
        // System.out.println("d2 > d3 ? " + (d1 > d3)); // 대소 비교 불가 에러
        System.out.println("d1.compareTo(d3) ? " + (d1.compareTo(d3))); // 0 (같음)
        System.out.println("d1.compareTo(d2) ? " + (d1.compareTo(d2))); // -2 (왼쪽이 작음)
        
        switch(d1) {
        	// Direction.EAST 불가 : switch문 문법
        	case EAST:
            	System.out.println("The direction is EAST.");
                break;
           	case SOUTH:
            	System.out.println("The direction is SOUTH.");
                break;
           case WEST :
           		System.out.println("The direction is WEST.");
                break;
          	case NORTH :
            	System.out.println("The direction is North.");
                break;
            default :
            	System.out.println("Invalid direction.");
                break;
        }
        
        Direction[] dArr = Direction.values(); // 열거형의 모든 상수를 배열로 반환
        
        for(Direction d : dArr)  // for(Direction d : Direction.values())
        	System.out.printf("%s=%d%n", d.name(), d.ordinal()); // ordinal : 순서, 열거형 객체에 값을 주면 ordinal값과 다를 수 있음
    }
}

  • 열거형 상수는 객체이기 때문에 equals()와 compareTo()만 되지만 ==도 허용

movie

열거형에 멤버 추가하기

  • 불연속적인 열거형 상수의 경우 원하는 값을 괄호 안에 적는다
// 괄호 : 생성자 호출을 의미
enum Direction { EAST(1), SOUTH(5), WEST(-1), NORTH(10) }
  • 괄호()를 사용하려면 인스턴스 변수와 생성자를 새로 추가해 줘야 한다
enum Direction {
	EAST(1), SOUTH(5), WEST(-1), NORTH(10); // 끝에 ; 추가 필요
    
    private final int value; // 정수를 저장할 인스턴스 변수
    (private) Direction(int value) { // 생성자 추가
    	this.value = value;
    }
    
    public int getValue() {
    	return value;
    }
}
  • 열거형의 생성자는 묵시적으로 private 이므로 외부에서 객체 생성 불가
Direction d = new Direction(1); // 에러, 열거형의 생성자는 외부에서 호출 불가

예제

enum Durection2 {
	EAST(1, ">"), SOUTH(2, "V"), WEST(3, "<"), NORTH(4, "^");
    0
    private static final Direction2[] DIR_ARR = Direction2.values();
    private final int value;
    private final String symbol;
    
    Direction2(int value, String symbol) { // 접근 제어자 private 생략
    	this.value = value;
    	this.symbol = symbol;
    }
    
    public int getValue() {
    	return value;
    }
    public String getSymbol() {
    	return symbol;
    }
    
    public static Direction2 of(int dir) {
    	if(dir < 1 || dir > 4)
        	throw new IllegalArgumentException("Invalid value :" + dir);
        return DIR_ARR[dir - 1];
   }
   
   // 방향을 회전시키는 메서드. num 값만큼 90도씩 시계빵향 회전
   public Direction2 rotate(int num) {
   		num = num % 4;
        
        if(num < 0) num += 4; // num이 음수일때는 시계 반대 방향으로 회전
        return DIR_ARR[(value-1+num) % 4];
   }
   
   public String toString() {
   		return name() + getSymbol();
   }
}

class Ex12_6 {
	public static void main(String[] args) {
    	for(Direction2 d : Direction2.values())
        	System.out.printf("%s=%d%n", d.name(), d.getValue());
            // EAST=1, SOUTH=2, WEST=3, NORTH=4
            // d.ordinal() 로 변경 시 0, 1, 2, 3 으로 순서대로 나옴
            
        Direction2 d1 = Direction2.EAST;
        Direction2 d2 = Direction2.of(1);
        
        System.out.printf("d1=%s, %d%n", d1.name(), d1.getValue());  // d1=EAST, 1
        System.out.printf("d2=%s, %d%n", d2.name(), d2.getValue());  // d2=EAST, 1
        System.out.println(Direction2.EAST.rotate(1));
        // SOUTHV
        System.out.println(Direction2.EAST.rotate(2));
        // WEST<
        System.out.println(Direction2.EAST.rotate(-1));
        // NORTH^
        System.out.println(Direction2.EAST.rotate(-2));
        // WEST<
  }
}

이전에 적용한 Enum

@Getter
public enum MembershipType {
	READY(0),
	STARTING(1),
	PAUSE(2),
	EXTENSION(3),
	RESTART(4);

	private int status;

	MembershipType(int status) {
		this.status = status;
	}
}

@Getter
public enum HistoryType {
	PAYMENT(0),
	EXTENSION(1),
	PAUSE(2),
	RESTART(3),
	EXPIRATION(4);

	private int status;

	HistoryType(int status) {
		this.status = status;
	}
}
GymHistory tmp2 = GymHistory.builder()
			.apt(user.getApt())
			.gym(updateMembership.getGym())
			.price(gymTicket.getPrice())
			.name(gymTicket.getName())
			.startDate(startDate)
			.endDate(endDate)
			.status(HistoryType.EXTENSION.getStatus()) // 연장 history
			.paymentMethod(method)
			.user(user)
			.userName(userName != null ? userName : "알수없음")
			.contact(contact != null ? contact : "알수없음")
			.address(userAddress != null ? userAddress : "알수없음")
			.build();
  • 이전에는 status에 상수로 넣고 주석으로 어떤 상태인지 나타냈었는데
    가독성 향상 및 오타 방지를 위해 Enum을 도입했었다.
// 변경 전
.status(1) // 1은 연장을 나타냄
// 변경 후
.status(HistoryType.EXTENSION.getStatus()) // 연장 history
  • 이전에는 단순히 Enum 복붙 사례를 가져다가 변수명과 값만 바꿨었는데,
    이번 영상들을 통해 어떤 식으로 Enum 객체 생성자가 호출하는지를 알고 넘어간 것 같다!
    • 괄호를 사용하여 정수값 지정 : 내부 인스턴스 변수 + 생성자
    • 생성자는 private가 생략된 형태로 외부에서 new 키워드로 생성 불가
      • 클래스로딩 시 한번만 생성되고, 메서드 영역에 로드됨
    • @Getter 어노테이션으로 각각의 Enum 객체 get메서드 구현
      • getStatus()와 같은 형태 가능
profile
비슷한 어려움을 겪는 누군가에게 도움이 되길

0개의 댓글

관련 채용 정보