인터페이스 기반 상수 정의
인터페이스 내에 선언된 변수는 public, static, final이 선언된 것으로 간주한다.
자바 5 이전에는 연관된 상수들을 하나의 인터페이스로 묶어서 선언하는 방법을 사용했다.
하지만 이러한 방식은 잘못된 메소드 호출임에도 에러를 발생시키지 않는다는 문제점이 있다.
interface Animal {
int DOG = 1;
int CAT = 2;
}
interface Person {
int MAN = 1;
int WOMAN = 2;
}
class Const_Interface_NonSafe {
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;
}
}
}
// 실행 결과
남자입니다.
남자입니다.
이러한 문제의 해결을 위해 자바 5에서 열거형이 등장했다.
열거형
- 열거형 안에 위치한 이름들을 열거형 값(Enumerated Values)이라 한다.
- 열거형은 클래스와 성격이 유사하다.
- 열거형은 java.lang.Enum<E> 클래스를 상속한다.
- 그리고 Enum<E>는 Object 클래스를 상속한다.
- 이러한 측면에서 열거형은 클래스라고 볼수 있다.
- 참조변수 선언이 가능하다.
- 단, 참조변수는 해당 열거형 내에 선언된 '열거형 값'만 대입이 가능하다
- case문에서 표현의 간결함을 위해 열거형 값의 이름만 명시하기로 약속되어 있다.
enum Scale { // 열거형 Scale 정의
DO, RE, MI, FA, SO, RA // 열거형 값
}
class Enum {
public static void main(String[] args) {
Scale sc = Scale.DO; // 열거형 참조변수 선언
System.out.println(sc);
switch (sc) {
case DO: // Scale.Do가 아닌 열거형 값의 이름만 명시
System.out.println("도~");
break;
case RE:
System.out.println("레~");
break;
case MI:
System.out.println("미~");
break;
case FA:
System.out.println("파~");
break;
default:
System.out.println("솔~ 라~");
break;
}
}
}
// 실행 결과
DO
도~
💡 열거형 기반의 상수 정의로 개선된 부분
- 열거형 참조변수는 해당 열거형 내에서 선언된 열거형 값만 대입이 가능하기 때문에 who 메소드에 전달되는 인자 man은 Person 열거형 값만 받을 수 있게 된다.
- 따라서 who(Animal.Dog)는 컴파일 과정에서 자료형 불일치로 인한 오류를 발생시킨다.
enum Animal {
DOG, CAT
}
enum Person {
MAN, WOMAN
}
class Enum_Safe {
public static void main(String[] args) {
who(Person.MAN); // 정상적인 메소드 호출
// who(Animal.DOG); // 비정상적 메소드 호출이 컴파일 에러로 이어짐
}
public static void who(Person man) {
switch(man) {
case MAN:
System.out.println("남자입니다");
break;
case WOMAN:
System.out.println("여자입니다");
break;
}
}
}
// 실행 결과
남자입니다.
클래스 내 열거형 정의
- 클래스 내에 열거형이 정의되면 열거형 값들은 해당 클래스 내에서만 사용 가능하다.
(특정 클래스 내에서만 사용하고자 하는 열거형 값이 있다면, 해당 클래스 내에 열거형을 정의해서 사용하도록 하자)
class Customer {
enum Gender { // 클래스 내에 정의된 열거형 Gender
MALE, FEMALE
}
private String name;
private Gender gen;
Customer(String n, String g) {
name = n;
if (g.equals("man"))
gen = Gender.MALE;
else
gen = Gender.FEMALE;
}
@Override
public String toString() {
if(gen == Gender.MALE)
return "Thank you, Mr " + name;
else
return "Thank you, Mrs " + name;
}
}
class Enum_ClassInner {
public static void main(String[] args) {
Customer cus1 = new Customer("wuga", "man");
Customer cus2 = new Customer("jeong", "woman");
System.out.println(cus1);
System.out.println(cus2);
}
}
// 실행 결과
Thank you, Mr wuga
Thank you, Mrs jeong
열거형 값의 정체
열거형 값은 해당 자료형의 인스턴스이다.
enum Person {
MAN, WOMAN;
}
✅ 열거형 값이 인스턴스라는 증거1
enum Person {
MAN, WOMAN;
@Override
public String toString() {
return "I am a dog person ♡"; // "나는 개를 사랑하는 사람입니다."
}
}
class Enum_Const {
public static void main(String[] args) {
System.out.println(Person.MAN); // toString 메소드의 반환 값 출력
System.out.println(Person.WOMAN); // toString 메소드의 반환 값 출력
}
}
// 실행 결과
I am a dog person ♡
I am a dog person ♡
- 위 예제에서 다음 문장을 통해 toString 메소드가 호출되었음을 보인다.
- System.out.println(Person.Man);
- 이는 즉 MAN, WOMAN이라는 열거형 값 Person 인스턴스를 참조하는 참조변수임을 나타낸다.
✅ 열거형 값이 인스턴스라는 증거2
enum Person {
MAN, WOMAN;
private Person() { // 생성자 정의
System.out.println("Person constructor called");
}
@Override
public String toString() {
return "I am a dog person ♡"; // "나는 개를 사랑하는 사람입니다."
}
}
class Enum_Constructor {
public static void main(String[] args) {
System.out.println(Person.MAN); // toString 메소드의 반환 값 출력
System.out.println(Person.WOMAN); // toString 메소드의 반환 값 출력
}
}
// 실행 결과
Person constructor called
Person constructor called
I am a dog person ♡
I am a dog person ♡
- 열거형 정의에도 클래스와 같이 생성자가 없으면 디폴트 생성자가 삽입된다.
- 다만 생성자가 private으로 선언되어 직접 인스턴스를 생성하는 것이 불가능 하다는 차이점이 있다.
- 위 예제 와 같이 열거형 생성자를 정의해주니 두번의 생성자 호출이 이뤄진 것을 확인할 수 있다.
- 이는 MAN, WOMAN이라는 열거형 값 Person 인스턴스를 참조하는 참조변수임을 나타낸다.
참고
- 다음 예제와 같이 Person 클래스 내에서 Person형 참조변수 선언과, Person 인스턴스 생성이 가능하다.
- 일반적으로는 이러한 클래스 정의를 하지 않지만, 특정 자료구조를 직접 정의해야 하는 경우 이러한 특성을 활용한다.
class Person {
// Person 클래스 내 Person형 참조변수와 인스턴스 생성
public static final Person MAN = new Person();
public static final Person WOMAN = new Person();
@Override
public String toString() {
return "I am a dog person ♡"; // "나는 개를 사랑하는 사람입니다."
}
}
class InClassInst {
public static void main(String[] args) {
System.out.println(Person.MAN);
System.out.println(Person.WOMAN);
}
}
// 실행 결과
I am a dog person ♡
I am a dog person ♡
인자를 전달받는 열거형 생성자 정의
- 열거형의 생성자는 무조건 private으로 선언해야 한다.
- 열거형 값의 선언에서 소괄호()를 통해 생성자에 인자를 전달할 수 있다.
- 또한 열거형도 Object 클래스를 상속하는 일종의 클래스이기 때문에 생성자 및 인스턴스 변수와 메소드 모두 선언할 수 있다.
enum Person {
MAN(29), WOMAN(25);
int age;
private Person6(int age) {
this.age = age;
}
@Override
public String toString() {
return "I am " + age + " years old";
}
}
class Enum_Constructor_Parameter {
public static void main(String[] args) {
System.out.println(Person.MAN);
System.out.println(Person.WOMAN);
}
}
// 실행 결과
I am 29 years old
I am 25 years old
'☕ Java > 이론' 카테고리의 다른 글
[Java] 함수형 인터페이스 (0) | 2022.02.03 |
---|---|
[Java] 람다 (0) | 2022.01.28 |
[Java] 네스티드 클래스, 이너 클래스 (0) | 2022.01.27 |
[Java] 가변인자, 어노테이션 (0) | 2022.01.26 |
[Java] 컬렉션 기반 알고리즘 (sort, binarySearch, copy) (0) | 2022.01.25 |
[Java] Queue 컬렉션 클래스 (0) | 2022.01.25 |
[Java] Set 컬렉션 클래스 (0) | 2022.01.25 |
[Java] List 컬렉션 클래스 (0) | 2022.01.25 |