Enum(열거형)
GOALS:
- Enum의 기본적인 개념을 이해하고 설명할 수 있다.
- Enum이 등장하게 된 배경에 대해서 이해하고, 그 장점에 대해 설명할 수 있다.
- Enum의 문법 요소를 이해하고 적절하게 사용할 수 있다.
Enum : enumerated type은 여러 상수들을 보다 편리하게 선언할 수 있도록 함.
자바에서 상수는 final 키워드를 이용하여 선언했었다.
다만 근데 이 키워드로 상수를 할당하면, 상수명이 중복되는 경우가 생긴다.
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int FALL = 3;
public static final int WINTER = 4;
public static final int DJANGO = 1;
public static final int SPRING = 2; // 계절의 SPRING과 중복 발생!
public static final int NEST = 3;
public static final int EXPRESS = 4;
이렇게 되어 있을 때 일차적으로 interface 키워드를 사용하여 해결할 순 있다.
예를 들어 아래처럼.
interface Seasons {
int SPRING = 1, SUMMER = 2, FALL = 3, WINTER = 4;
}
interface Frameworks {
int DJANGO = 1, SPRING = 2, NEST = 3, EXPRESS = 4;
}
다만 이렇게 했을 경우, Season.SPING == Frameworks.DJANGO 가 true가 나와 타입 안정성이 떨어진다.
그래서 객체의 생성으로 방지를 할 수 있지만 코드가 길어져 만들어진 것이 enum 키워드가 생겼다.
예를 들어서
enum Seasons { SPRING, SUMMER, FALL, WINTER }
enum Frameworks { DJANGO, SPRING, NEST, EXPRESS }
와 같이 코드를 선언시 코드가 간결해진다.
그래서 위와 같이 선언했을 경우를 활용하는 코드를 작성하면,
enum Seasons { SPRING, SUMMER, FALL, WINTER }
enum Frameworks { DJANGO, SPRING, NEST, EXPRESS }
public class Main {
public static void main(String[] args) {
Seasons seasons = Seasons.SPRING;
switch (seasons) {
case SPRING:
System.out.println("봄");
break;
case SUMMER:
System.out.println("여름");
break;
case FALL:
System.out.println("가을");
break;
case WINTER:
System.out.println("겨울");
break;
}
}
}
와 같이 활용할 수 있다.
위의 같은 경우에는 Seasons.SPRING으로 객체를 만들었기에 출력은 봄 이 나온다.
그래서 enum 을 일반화해서 보자면
enum 열거형이름 {
상수명1 // 정수값 0이 할당됨
상수명2 // 1이 할당됨
상수명3 // 2이 할당됨
...
}
이 된다. 그렇다면 상수명 또는 정수값은 어떻게 따로따로 받을 수 있을까?
이는 method 형태로 만들어져 있으니 테이블을 통해서 알아보자.
Generic
GOALS:
- 제네릭의 장점을 이해한다.
- 제네릭 클래스를 정의하고 활용할 수 있다.
- 제네릭 메서드를 정의하고 활용할 수 있다.
Generic이라는 단어에서도 느낌이 온 것처럼,
원래 어떠한 method에선 parameter의 타입을 지정해줘야만 했다. 예를 들어
class Basket {
private String item;
Basket(String item) {
this.item = item;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
}
이처럼 Basket은 String 다입의 데이터만 받을 수 있었다.
하지만 제네릭을 사용한다면, Basket의 parameter를 모든 타입으로 받을 수 있다. 예를 들어
class Basket<T> {
private T item;
public Basket(T item) {
this.item = item;
}
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
}
이처럼 T 라는 키워드를 데이터 타입 자리에 넣어주면 사용하는 argument에 따라 데이터를 저장해준다.
String이 들어오면 String으로, Integer가 들어오면 Integer로…
이 과정은 객체를 생성할 때 일어난다. 예를 들어
Basket<Integer> basket2 = new Basket<Integer>(1);
이렇게 argument를 주기 위해 안에 데이터 타입을 넣어 준다.
위와 같이 객체를 생성하면 BasketT
클래스는 아래와 같이 코드가 변환한다.
class Basket<Integer> {
private Integer item;
public Basket(Integer item) {
this.item = item;
}
public Integer getItem() {
return item;
}
public void setItem(Integer item) {
this.item = item;
}
}
Integer 말고도, Double, Boolean, String 등등으로 객체를 생성 가능하다. 그래서
class Basket<T> {
private T item;
static T item2;
public Basket(T item) {
this.item = item;
}
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
}
static T item2 와 같이 static이 붙은 변수나 method는 argument로 사용할 수 없다.
그리고 클래스에 사용할 때 interface를 사용할 수 있고, 상속 또한 가능하다. 예를 들어
interface Plant { ... }
class Flower implements Plant { ... }
class Rose extends Flower implements Plant { ... }
class Basket<T extends Plant> {
private T item;
...
}
class Main {
public static void main(String[] args) {
// 인스턴스화
Basket<Flower> flowerBasket = new Basket<>();
Basket<Rose> roseBasket = new Basket<>();
}
}
위와 같이 정의할 수 있다. 또한 예상 가능하듯이 method에도 사용 가능하다.