[윤성우의 열혈 Java 프로그래밍] Chapter 25 - 열거형, 가변 인자 그리고 어노테이션
카테고리: Java lang
태그: java
25-1. 열거형
열거형: ‘의미가 부여된 이름’을 갖는 ‘상수’의 선언
- 인터페이스 기반의 상수 정의
열거형 등장 이전의 모습을 보자.
interface Animal {
int DOG = 1;
int CAT = 2;
}
interface Person {
int MAN = 1;
int WOMAN = 2;
}
class NonSafeConst {
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;
}
}
}
열거형 등장 이전에는 보다싶이 인터페이스를 이용하여 의미를 가진 상수를 표현했다.
다만, 이런 방식의 경우 위의 코드와 같이 개발자의 의도와는 다르게
Person.MAN에 Animal.DOG이 전달되더라도 컴파일 단계에서 오류가 발견되지 않는다.
- 자료형의 부여를 돕는 열거형
enum Scale {
DO, RE, MI, FA, SO, RA, TI
}
열거형은 다음과 같이 정의한다.
그 안에 위치한 이름들을 가리켜 ‘열거형 값’, Enumerated Values
라고 한다.
다음과 같이 Scale형 변수를 선언하고, switch문을 구성할 수도 있다.
enum Scale {
DO, RE, MI, FA, SO, RA, TI
}
class SimpleEnum {
public static void main(String[] args) {
Scale sc = Scale.DO; // Scale형 참조변수 선언
System.out.println(sc);
switch(sc) {
case 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("솔~ 라~ 시~ ");
}
}
}
- 클래스 내에 정의가 가능한 열거형의 정의
특정 클래스 내에서만 사용하고 싶은 열거형 값이 있다면, 해당 클래스 내에 열거형을 정의하는 방법도 있다.
class Customer {
enum 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 InnerEnum {
public static void main(String[] args) {
Customer cus1 = new Customer("Brown", "man");
Customer cus2 = new Customer("Susan Hill", "woman");
System.out.println(cus1);
System.out.println(cus2);
}
}
- 열거형 값의 정체
enum Human {
MAN(29), WOMAN(25);
int age;
private Human(int age) {
this.age = age;
System.out.println("Human Constructor called");
}
@Override
public String toString() {
return "I am " + age + " years old!";
}
}
public class EnumExample {
public static void main(String[] args) {
System.out.println(Human.MAN);
System.out.println(Human.WOMAN);
}
}
위의 실행 결과를 통해 다음을 알 수 있다.
- 생성자가 호출되었다.
- toString 메소드가 호출되었다.
모든 열거형은 java.lang.Enum
열거형의 정의에도 생성자가 없으면 디폴트 생성자가 삽입되지만, 이 생성자는 private
으로 선언되어 직접 인스턴스를 생성하는 것이 불가능할 뿐이다.
정리하자면,
- 열거형도
Object
클래스를 상속하는 일종의 클래스이다. - 따라서 생성자는 물론, 인스턴스 변수와 메소드 둘 다 가질 수 있다.
- 다만 모든 생성자를
private
로 선언해야 하기 때문에 ‘열거형 값’이 유일한 인스턴스 생성 방법이라는 차이가 있을 뿐이다.
25-2. 매개변수의 가변 인자 선언
…이 삽입된 이 메소드의 매개변수 선언을 가리켜 ‘가변 인자 선언’이라 한다.
- 매개변수의 가변 인자 선언과 호출
class Varargs {
public static void showAll(String... vargs) {
System.out.println("LEN: " + vargs.length);
for(String s : vargs)
System.out.print(s + '\t');
System.out.println();
}
public static void main(String[] args) {
showAll("Box");
showAll("Box", "Toy");
showAll("Box", "Toy", "Apple");
}
}
자바에서는 인자들을 받아 배열로 만들고, 그 배열의 참조값을 참조변수가 참조하도록 한다.
- 가변 인자 선언에 대한 컴파일러의 처리
매개변수의 가변 인자 선언은 자바 5에서 추가된 문법이다.
기존 코드는 다음과 같고, 이것이 컴파일러가 변환하는 형태이다.
// 컴파일러 번역 전
public static void showAll(String... vargs) {...}
public static void main(String[] args) {
showAll("Box");
showAll("Box", "Toy");
showAll("Box", "Toy", "Apple");
}
// 컴파일러 번역 후
public static void showAll(String[] vargs) {...}
public static void main(String[] args) {
showAll(new String[]{"Box"});
showAll(new String[]{"Box", "Toy"});
showAll(new String[]{"Box", "Toy", "Apple"});
}
25-3. 어노테이션(Annotations)
자바 컴파일러에게 메시지를 전달하는 목적의 메모
- 어노테이션의 설명 범위
어노테이션은 자바 5에서 소개되었고, 당시 소개된 어노테이션 타입 세 가지는 다음과 같다.
@Override
@Deprecated
@SuppressWarnings
- @Override
interface Viewable {
public void showIt(String str);
}
class Viewer implements Viewable {
@Override
public void showIt(String str) {
System.out.println(str);
}
};
class AtOverride {
public static void main(String[] args) {
Viewable view = new Viewer();
view.showIt("Hello Annotations");
}
}
상위 클래스의 메소드 오버라이딩 또는 인터페이스에 선언된 추상 메소드의 구현이다.
이에 어긋난 메소드의 정의가 이뤄지면 컴파일 오류로 이어져서 개발자로 하여금 잘못된 부분을 확인할 수 있게 해준다.
interface Viewable {
public void showIt(long num);
}
class Viewer implements Viewable {
@Override // 이 어노테이션이 없으면 컴파일러는 단순히 오버로딩으로 간주하고 컴파일 단계에서 오류를 뱉지 않음
public void showIt(int num) {
System.out.println(str);
}
};
class AtOverride {
public static void main(String[] args) {
Viewable view = new Viewer();
view.showIt(777);
}
}
- @Deprecated
문제의 발생 소지가 있거나 개선된 기능의 다른 것으로 대체되어서 더 이상 필요 없게 되었음을 뜻하는 말로,
아직은 호환성 유지를 위해 존재하지만 이후에 사라질 수 있는 클래스 또는 메소드를 가리켜 Deprecated 되었다고 한다.
interface Viewable {
@Deprecated
public void showIt(String str); // 컴파일러가 경고함!
public void brShowIt(String str);
}
class Viewer implements Viewable {
@Override
public void showIt(String str) {
System.out.println(str);
}
@Override
public void brShowIt(String str) {
System.out.println('[' + str + ']');
}
}
class AtDeprecated {
public static void main(String[] args) {
Viewable view = new Viewer();
view.showIt("Hello Annotations"); // 컴파일러가 경고함!
view.brShowIt("Hello Annotations");
}
}
- @SuppressWarnings
컴파일러가 경고 메시지를 전달하는 특정 상황에 대해서, 경고 메시지를 전달하지 말라고 요청할 때 어노테이션 타입 @SuppressWarnings를 사용한다.
interface Viewable {
@Deprecated
public void showIt(String str);
public void brShowIt(String str);
}
class Viewer implements Viewable {
@Override
@SuppressWarnings("deprecation") // 컴파일러의 경고 무시
public void showIt(String str) {
System.out.println(str);
}
@Override
public void brShowIt(String str) {
System.out.println('[' + str + ']');
}
};
class AtSuppressWarnings {
@SuppressWarnings("deprecation") // 컴파일러의 경고 무시
public static void main(String[] args) {
Viewable view = new Viewer();
view.showIt("Hello Annotations");
view.brShowIt("Hello Annotations");
}
}
그리고 다음과 같이 동시에 여러 경고 유형에 대해 @SuppressWarnings 선언을 할 수도 있다.
@SuppressWarnings({"fallthrough", "deprecation"})
댓글 남기기