쿠릉쿠릉 쾅쾅
쿠릉쿠릉 쾅쾅
쿠릉쿠릉 쾅쾅
250x250
전체 방문자
오늘
어제
  • 분류 전체보기
    • HTML CSS
    • 잡담
    • 프로그래밍 꿀팁 사이트
    • 코딩 도서
    • [자바]
      • 디자인 패턴
      • 자바의 정석 - 3판
      • 자바
      • 자바 문법
    • git
    • [TDD]
    • 개발 서적 독후감
      • 클린 코더
      • 토비 스프링3
      • 객체지향의 사실과 오해
      • 모던 자바 인 액션
      • 엘레강트 오브젝트
    • CS
      • 운영체제
      • HTTP
    • [SQL]
      • SQL 기초
      • 혼자공부하는SQL
    • [ Spring ]
      • REST API
      • Spring Toy
      • Spring 에러
      • Spring
      • Spring 입문
      • Spring 핵심 원리
      • SpringMVC 1편
      • SpringMVC 2편
      • Spring Boot를 이용한 RESTful We..
      • Batch
    • [JPA]
      • JPA
      • JPA 에러
      • JPA 프로그래밍 - 기본편
      • 스프링 부트와 JPA 활용 1 - 웹 애플리케이..
      • 실전! 스프링 부트와 JPA 활용2 - API 개..
      • 실전! 스프링 데이터 JPA
      • 실전! Querydsl
    • 인텔리제이
    • [DB]
      • DB
      • H2
    • Gradle
    • 면접
    • [알고리즘]
      • 알고리즘
      • 자료구조
      • 자바 알고리즘 공부
    • [프로젝트]
    • 쿠릉식 객체지향 사고
    • 리눅스

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 자바
  • querydsl
  • 알고리즘
  • Git
  • REST API
  • http
  • 스프링부트
  • 재귀
  • MVC
  • 백준
  • Spring
  • springboot
  • SQL
  • 스프링
  • 깃허브
  • java
  • 자료구조
  • 함수형인터페이스
  • JPA
  • GitHub

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
쿠릉쿠릉 쾅쾅

쿠릉쿠릉 쾅쾅

[자바]/자바

[Java] 열거형 (enum)

2022. 1. 26. 16:32
728x90

 

📍 학습 목표 
열거형(enum)은 자바5에서 추가된 자료형으로 '의미가 부여된 이름'을 갖는 '상수'의 선언에 그 목적이 있다.
열거형(enum)가 추가 되기 전/후를 비교해서 어떤 점이 달라졌고 열거형이 무엇인지 알아보자!

 

 

열거형(enum) 추가 되기 전

인터페이스 기반의 상수 정의 

interface Scale {
	int DO = 0; int RE = 1; int MI = 2; int FA = 3;
	int SO = 4; int RA = 5; int SI = 6;
}
  • 인터페이스 내에 선언된 변수는 public, static, final이 선언된 것으로 간주한다.

 

🔍 인터페이스 기반의 상수 정의의 문제점

public  class Prac {	

    public static void main (String[] args) {    
    	who(Person.MAN);
    	who(Animal.DOG);
    	
    }
    
    public static void who(int man) {
    	switch(man) {
    	
    	case Person.MAN:
    		System.out.println("남성 손닙입니다.");
    		break;
    		
    	case Person.WOMAN:
    		System.out.println("여성 손님입니다.");
    		break;
    		
    	}  // end of switch
    	
    } 
    
}


interface Animal {
	int DOG = 1;
	int CAT = 2;
}

interface Person {
	int MAN = 1;
	int WOMAN = 2;
}
남성 손닙입니다.
남성 손닙입니다.
  • Person.MAN의 값이 1이다. 하지만 Animal.DOG의 값도 1이다. 그렇기 때문에 who() 메서드에 어떤 인터페이스의 상수가 오든 int 타입일 경우 컴파일 오류와 실행 오류를 발생시키지 않는다. 
  • 이런 문제를 해결하기 위해서 자바5에서 열거형(enum)이 추가됐다.

 

 

public  class Prac {	

    public static void main (String[] args) {    
    	System.out.println(Animal.CAT == Person.WOMAN);
    } 
    
}


interface Animal {
	int DOG = 1;
	int CAT = 2;
}

interface Person {
	int MAN = 1;
	int WOMAN = 2;
}
true
  • 인터페이스 기반의 상수를 정의의 문제점을 더 자세히 보자면, Animal.CAT 과 Person.WOMAN은 서로 값은 같지만 타입이 달라서 false 값이 나와야 하지만 인터페이스 기반의 상수 정의에서는 true가 나온다. 

 

 

열거형(enum) 추가

열거형 (enum)

  • 모든 열거형은 java.lang.Enum 클래스의 자손이다.
  • 열거형은 서로 관련된 상수를 편리하게 선언하기 위한 것으로 여러 상수를 정의할 때 사용하면 유용하다.
  • 열거형은 '타입에 안전한 열거형(typesafe enum)'이라서 실제 값이 같아도 타입이 다르면 컴파일 에러가 발생한다.
    • 인터페이스 기반의 상수 정의의 문제점 해결!
    • enum 타입은 고정된 상수들의 집합으로 런타임이 아닌 컴파일 타임에 모든 값을 알고 있어야한다.
  • 상수의 값이 바뀌면, 해당 상수를 참조하는 모든 소스를 다시 컴파일 해야한다. 하지만 열거형 상수를 사용하면, 기존의 소스를 다시 컴파일 하지 않아도 된다.
  • 열거형 상수간의 비교에는 ==, equals() 를 사용할 수 있다. 그러나 ==의 속도가 더 빠르다.
    • ==는 객체의 주소 비교이다. 열거형의 상수는 값이 바뀌지 않으므로 ==로 비교 가능한 것이다.
  • <, > 같은 비교 연산자는 사용할 수 없으나 compareTo()는 사용 가능하다.
    • compareTo()로 비교할 때, 두 열거형 상수의 ordinal() 값을 서로 뺴준다. 비교 대상이 같으면 0. 왼쪽이 크면 양수, 오른쪽이 크면 음수를 반환한다.
    • Enum 클래스는 Comparable<E>를 구현한 클래스다. 
  • 열거형의 생성자는 private만 선언할 수 있으나 생략 가능하다.
    • 열거형의 생성자는 외부에서 호출불가

 

 

🔍 열거형의 정의

💡 방법1

enum 열거형이름 {상수명A, 상수명B, ...}

 

💡 방법2

enum 열거형이름 {상수명A(1), 상수명B(2), ...}
  • 열거형 상수의 값이 불연속적인 경우에는 열거형 상수의 이름 옆에 원하는 값을 괄호()와 함께 적어주면 된다.
  • 지정된 값을 저장할 수 있는 인스턴스 변수와 생성자를 새로 추가해줘야 한다.
    • 이 때 열거형 상수를 먼저 정의한 다음에 열거형 상수 마지막에 ';' 를 붙인 후에 다른 멤버들을 추가해야한다.
  • 하나의 열거형 상수에 여러 값을 지정할 수도 있다. 다만 그에 맞게 인스턴스 변수와 생성자 등을 새로 추가해야 한다.
더보기
더보기

예제1

enum Direction {
	EAST(1), SOUTH(5), WEST(-1), NORTH(10);  // 끝에 ; 추가할 것
	
	private int value;
	
	Direction(int value) {
		this.value = value;
	}
}

 

예제2

enum Direction {
	EAST(1, ">"), SOUTH(5, "V"), WEST(-1, "<"), NORTH(10, "^");
	
	private int value;
	private String symbol;
	
	Direction(int value, String symbol) {
		this.value = value;
		this.symbol = symbol;
	}
}

 

 

🔍 Enum 클래스의 메서드

메서드 설명
Class<E> getDeclaringClass() 열거형의 Class객체를 반환
String name() 열거형 상수의 이름을 문자열로 반환
int ordinal() 열거형 상수가 정의된 순서를 반환 (0부터 시작)
static <T extends Enum<T>> valueOf(Class<T>, enumType,  String name) 지정된 열거형에서 name과 일치하는 열거형 상수를 반환
int compareTo(E o) 비교한다.
  • ordinal()이 열거형 상수에 정의된 순서를 반환하지만, 이 값을 열거형 상수의 값으로 사용하지 않는 것이 좋다. 이 값은 내부적인 용도로만 사용되기 위한 것이기 때문이다.

 

💡 컴파일러가 자동으로 추가해주는 메서드

메서드 설명
static E[] values() 열거형의 모든 상수를 배열에 담아 반환
static E valueOf(String name) 열거형 상수의 이름으로 문자열 상수에 대한 참조를 얻을 수 있다.

 

더보기
더보기
public  class Prac {	

    public static void main (String[] args) {    
 
    	Direction d = Direction.valueOf("WEST");
    	
    	System.out.println(d);
    	System.out.println(Direction.WEST == Direction.valueOf("WEST"));
    	
    }
}

enum Direction {
EAST, SOUTH, WEST, NORTH
}
WEST
true

 

 

🔍 예제

예제1

public  class Prac {	

    public static void main (String[] args) {    
    	Direction d1 = Direction.EAST;
    	Direction d2 = Direction.valueOf("WEST");
    	Direction d3 = Enum.valueOf(Direction.class, "EAST");
    	
    	System.out.println("d1 = " + d1);
    	System.out.println("d2 = " + d2);
    	System.out.println("d3 = " + d3);
    	
    	System.out.println();
    	
    	System.out.println("d1 == d2 ? " + (d1==d2));
    	System.out.println("d1 == d3 ? " + (d1==d3));
    	System.out.println("d1.equals(d3) ? " + d1.equals(d3));
    	System.out.println("d1.compareTo(d3) ? " + (d1.compareTo(d3)));
    	System.out.println("d1.compareTo(d2) ? " + (d1.compareTo(d2)));
    	
    	System.out.println();
    	
    	move(d1);
    	
    	System.out.println();
    	
    	Direction[] dArr = Direction.values();
    	
    	for(Direction d: dArr)
    		System.out.printf("%s = %d%n", d.name(), d.ordinal());
    	
    } 
    
    static void move(Direction dir) {
    	switch(dir) {
    	case EAST:
    		System.out.println("EAST");  // Direction.EAST라고 쓰면 안된다.
    		break;
    	case SOUTH:
    		System.out.println("SOUTH");
    		break;
    		
    	case WEST:
    		System.out.println("WEST");
    		break;
    		
    	case NORTH:
    		System.out.println("NORTH");
    		break;
    		
    	default:
    		System.out.println("Invalid diraction");
    	}  // end of switch
    	
    	
    }
    
}

enum Direction {
EAST, SOUTH, WEST, NORTH
}
d1 = EAST
d2 = WEST
d3 = EAST

d1 == d2 ? false
d1 == d3 ? true
d1.equals(d3) ? true
d1.compareTo(d3) ? 0
d1.compareTo(d2) ? -2

EAST

EAST = 0
SOUTH = 1
WEST = 2
NORTH = 3
  • swtich문의 조건식에도 열거형을 사용할 수 있다.
  • 주의할 점은 case문에 열거형의 이름은 적지 않고 상수의 이름만 적어줘야한다.

 

 

예제2

public  class Prac {	

    public static void main (String[] args) {    
    	
    	for(Direction d : Direction.values())
    		System.out.printf("%s = %d%n", d.name(), d.getValue());
    	
    	Direction d1 = Direction.EAST;
    	Direction d2 = Direction.of(1);
    	
    	System.out.println();
    	
    	System.out.printf("d1 = %s, %d%n", d1.name(), d1.getValue());
    	System.out.printf("d2 = %s, %d%n", d2.name(), d2.getValue());
    	
    	System.out.println(Direction.EAST.rotate(1));
    	System.out.println(Direction.EAST.rotate(2));
    	System.out.println(Direction.EAST.rotate(-1));
    	System.out.println(Direction.EAST.rotate(-2));
    	
    }
    
}

enum Direction {
	EAST(1, ">"), SOUTH(5, "V"), WEST(-1, "<"), NORTH(10, "^");
	
	private static final Direction[] DIR_ARR = Direction.values();
	private int value;
	private String symbol;
	
	Direction(int value, String symbol) {
		this.value = value;
		this.symbol = symbol;
	}
	
	public int getValue() {return value;}
	public String getSymbol() {return symbol;}

	public static Direction of(int dir) {
		
		// 0~3 범위 벗어나면 예외 발생
		if(dir < 1 || dir > 4)
			throw new IllegalArgumentException("Invalid value : " + dir);
		
		return DIR_ARR[dir-1];
	}
	
	
	// 방향을 회전시키는 메서드. num의 값만큼 90도씩 시계방향으로 회전한다.
	public Direction 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();
	}
	
}
EAST = 1
SOUTH = 5
WEST = -1
NORTH = 10

d1 = EAST, 1
d2 = EAST, 1
SOUTHV
WEST<
NORTH^
WEST<

 

 

예제3 ㅡ 열거형에 추상 메서드 추가하기

public  class Prac {	

    public static void main (String[] args) {    
    	
    	System.out.println("bus fare = " + Transportation.BUS.fare(100));
    	System.out.println("train fare = " + Transportation.TRAIN.fare(100));
    	System.out.println("ship fare = " + Transportation.SHIP.fare(100));
    	System.out.println("airplane fare = " + Transportation.AIRPLANE.fare(100));
    	
    }
    
}

enum Transportation {
	BUS(100) {
		int fare(int distance) {
			return distance * BASIC_FARE;
		}
	},
	TRAIN(150){
		int fare(int distance) {
			return distance * BASIC_FARE+ 50;
		}
	},
	SHIP(100){
		int fare(int distance) {
			return distance * BASIC_FARE + 100;
		}
	},
	AIRPLANE(300){int fare(int distance) {return distance * BASIC_FARE * 2;}};
	
	
	protected int BASIC_FARE;  // protected로 해야 각 상수에서 접근 가능

	Transportation(int basicFare) {
		BASIC_FARE = basicFare;
	}

	public int getBasicFare() {return BASIC_FARE;}
	abstract int fare(int distance);
	

}
bus fare = 10000
train fare = 15050
ship fare = 10100
airplane fare = 60000
  • 열거형에 추상 메서드 fare(int distance)를 선언하면 각 열거형 상수가 이 주상 메서드를 반드시 구현해야 한다.
  • 각 열거형 상수가 추상 메서드 fare()를 각기 다른 내용으로 구현할 수 있어서 거리에 따라 요금을 계산하는 방식을 운송 수단마다 다르게 할 수 있다. 

 

 

728x90

'[자바] > 자바' 카테고리의 다른 글

[Java] Optional<T> 클래스  (0) 2022.02.07
[Java] 메서드 참조 (Method References)  (0) 2022.02.04
[Java] 함수형 인터페이스  (0) 2022.02.03
[Java] 내부 클래스, 네스티드(Nested) 클래스, 익명 클래스  (0) 2022.01.27
[Java] 애노테이션 (annotation)  (0) 2022.01.26
    '[자바]/자바' 카테고리의 다른 글
    • [Java] 메서드 참조 (Method References)
    • [Java] 함수형 인터페이스
    • [Java] 내부 클래스, 네스티드(Nested) 클래스, 익명 클래스
    • [Java] 애노테이션 (annotation)
    쿠릉쿠릉 쾅쾅
    쿠릉쿠릉 쾅쾅
    깃허브 주소 : https://github.com/kureung

    티스토리툴바