Java의 enum class는 enumeration 즉, '열거형 타입'을 의미하는 특수한 클래스 입니다. 개발에 필요한 열거형 상수들을 적절히 모아서 조금더 객체지향적으로 사용할 수 있는 고급 기술(?)이고, 소스코드에서 하드코딩 요소를 제거하는데 큰 도움이 됩니다.
Java enum 사용법 1 - 기본 형태
원소들간의 구분은 콤마(,)로 합니다. 그리고 enum 객체 역시 클래스이기 때문에 기본생성자가 있어야합니다. 물론, 아래와 같은 경우에는 생성자를 생략해도 Java가 디폴트 생성자를 만들어줍니다.
1 2 3 4 5 6 | public enum FontStyle { NORMAL, BOLD, ITALIC, UNDERLINE; FontStyle() { } } |
더 간단하게 인라인 클래스로 배열 선언하듯 사용할 수 있습니다. public으로 설정되어 있기 때문에 SampleClass의 인스턴스를 sample이라고 할 때 sample.FontStyle.NORMAL 처럼 접근할 수 있습니다.
1 2 3 4 | public enum SampleClass { public enum FontStyle { NORMAL, BOLD, ITALIC, UNDERLINE } ... } |
Java enum 사용법 2 - 추가 속성을 부여한 형태
아래는 enum 클래스의 각 원소에 별도 설명을 부여한 형태입니다. 사람이 이해하기 좋은 추가 속성을 지정했습니다. 각 원소 뒤에 괄호를 열고 primitive 속성으로 값을 지정하면 되고, 한개 이상의 경우 콤마로 구분하면됩니다. 단, 이경우에는 설명을 저자할 수 있는 필드가 하나 추가되고 생성자가 이 필드에 값을 설정할 수 있도록 인자가 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public enum FontStyle {<br /> NORMAL( "This font has normal style." ), BOLD( "This font has bold style." ), ITALIC( "This font has italic style." ), UNDERLINE( "This font has underline style." ); // 원소 설명 private String description; FontStyle(String description) { this .description = description; } public String getDescription() { return this .description; } } |
Java enum 사용법 3 - 에러코드/에러설명을 정의한 사례
단순히 에러코드만 반환하는 환경이 아니라 사용자 친숙한 코드/설명 쌍으로 결과를 반환하는경우 또는 로깅을 조금더 보기 좋게 하는 경우 사용법2를 응용해서 속성이 2개인 원소들로 구성된 enum을 만들 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public enum Errors { CLIENT_ERROR( "ERR_1001" , "This is client error." ), IO_ERROR( "ERR_1002" , "This is In/Out error." ), PARSE_ERROR( "ERR_1003" , "This is parse error." ), CONTEXT_ERROR( "ERR_1004" , "This is context error." ); private String code; private String desc; Errors(String code, String desc) { this .code = code; this .desc = desc; } public String getCode() { return this .code; } public String getDesc() { return this .desc; } } |
실제로 사용할 때는 그때 그때 다르지만 MYException으로 래핑하기 위해 아래와 같이 throw new를 이용하고 MYException 객체는 인자로 enum 클래스를 받게 했습니다.
1 2 3 4 5 6 7 | ... try { ... } catch (XXException e) { throw new MYException(Errors.CLIENT_ERROR); } |
Java enum을 사용하지 않는 경우
enum을 사용하지 않고 위의 폰트 스타일 예를 분기하는 경우, 가장 쉽운 방법은 아래와 같을 겁니다.
1 2 3 | if ( "NORMAL" .equals(fontStyle)) { ... } |
이걸 조금 더 구조화해서 개발을 한다면 아래와 같이 별도의 static 클래스를 만들고 int 값으로 비교를 하는 것도 좋은 방법이 되겠죠. 실제로 가장 일반적인 방법이기도 하고요. SWT에서도 UI위젯의 style 속성 정의를 이런 식으로 합니다.
1 2 3 4 5 6 7 8 9 10 | class FontStyle { public static final int NORMAL = 0 ; public static final int BOLD = 1 ; public static final int ITALIC = 2 ; public static final int UNDERLINE = 3 ; } if (fontStyle == FontStyle.NORMAL) { ... } |
기존 방법의 문제점
enum은 아래와 같은 문제점들을 해결하기 위해 만들어졌다고 합니다.
- 형검사를 하지 않으므로 오류발생 소지가 있다.
- 네임스페이스를 따르지 않으므로 중복의 소지가 있다.
- 순서 변경, 새로운 원소 추가에 취약합니다.
- 알아보기가 어렵습니다.
제가 생각하는 enum의 가장 큰 장점은 소스코드 속에서 사용자가 직접 입력한 String을 제거할 수 있다는 것과, 자동 형 검사를 통해 오류를 줄일 수 있다는데 있는것 같습니다. 게다가 enum 클래스는 Java VM 1.5에서 지원하지 시작한 기능으로 아무 추가 작업없이 그냥 쓸 수 있죠.
C로 개발을 할 때도 코드에서 사용할 데이터 구조체와 상수값을 별도의 헤더파일로 뽑아내어 소스코드의 하드코딩 요소들을 제거 했었습니다. enum 클래스 헤더파일을 별도의 클래스로 분리한 겁니다. 형검사라는 강력한 기능이 추가되어서 말이죠.
TODO 다음 번에는 iBatis에서 enum 지원 방법에 대해 작성을 해보려고 합니다.
참고자료
http://download.oracle.com/javase/1.5.0/docs/guide/language/enums.html
출처 - http://powerhan.tistory.com/140
java enum 정리 1 - 기본 개념
출처 - http://iilii.egloos.com/4343065/
java enum 정리 2 - enum의 메쏘드
출처 - http://iilii.egloos.com/4345025
java enum 정리 3 - java.lang.Enum 클래스와 enum의 실체
출처 - http://iilii.egloos.com/4346098
java enum - 보충
출처 - http://iilii.egloos.com/4835713
작년부터 안드로이드 공부를 하면서 조금씩 자바(java) 를 익혀가고 있다.
C++ 이랑 비슷하면서도 참 많이 다른 게 자바인데 그 중에 특히 enum 은 그동안 C++ 에서 불편해 하던 것이
다 구현도 있어서 참 편하다
예전에 C++ 관련 쓴 글은 아래 링크 참조
기본적인 enum 선언이나 사용법은 자바나 C++ 이나 비슷하다
public
enum Fruit { |
간단한 과일을 enum 으로 선언했는데, 각 enum 에 어떻게 값이 들어 가는 지는 아래 테스트 코드로 확인 가능
// 간단한enum 확인용테스트코드 |
C++ 처럼 자바도 enum 항목들이 0,1,2,3… 순서대로 저장되고 추가적으로 enum.name() 멤버 함수를 통해 enum 이름도 구할 수 있다.
사실 자바의 enum 은 class 이기 때문에 C++ 보다 훨씬 많은 기능이 가능하고, 예전에 C++ 에서 복잡하게 해 보려 했던 일들(위 링크 참조)이 기본적으로 구현되어 있다.
위 enum 선언을 조금 고쳐서 각 과일에 적당한 한글 이름과 색상 정보를 추가해 보자 .
Banana("바나나", "노랑"), Apple("사과", "빨강"), Lemon("레몬", "노랑"), Tomato("토마토", "빨강"), Melon("멜론", "초록"); private String m_sName; // 이름, 색상에맞는새로운생성자마련 // 과일색상가져오기함수 // 과일이름가져오기함수 |
코드는 정말 간단 ^^;
enum 옆에 ("바나나", "노랑") 같은 2가지 인자가 추가되었는데,
이처럼 자바는 enum 의 각 항목에 추가적인 정보를 개수 상관없이 마음대로 추가할 수 있다.
물론, 2가지 정보를 추가했기 때문에 enum 생성자를 변경해야 한다
Fruit(String sName, String sColor) |
이제 각 enum 별로 위 생성자대로 초기화가 진행 되어 각 항목별로 멤버 변수에 값이 할당 된다.
추가된 정보가 잘 들어 갔는지 확인하는 테스트 코드.
// 테스트코드 |
위 코드처럼 실행하면 아래 그림처럼, enum 의 각 항목 별로 순서, 원래 이름, 한글 이름, 색상까지 잘 나온다.
자바 enum 의 이러한 확장 기능을 잘 이용하면
데이터를 구분 짓는 ID 와 그 ID 와 연관된 추가적인 정보를 잘 관리 할 수 있어 정보를 체계적으로 다루는 데 아주 용이하다
(물론, 구조체나 클래스로 얼마든지 만들 수 있지만, 기본적으로 언어에서 제공한다는 것은 그만큼 사용하기 편하다는 뜻임)
출처 - http://eslife.tistory.com/537
간단한 선언
예)
- public enum Types {
- TYPE1, TYPE2, TYPE3;
- }
String 값을 대입
선언 예)
- public enum Types {
- TYPE1("Type 1"),
- TYPE2("Type 2"),
- TYPE3("Type 3");
- private String name;
- Types(String name) {
- this.name = name;
- }
- @Override
- public String toString() {
- return name;
- }
- }
사용 예)
- package com.enumtest;
- public class EnumTest {
- public static void main(String[] args) throws Exception {
- Types type = Types.TYPE1;
- System.out.println(type);
- }
- }
결과:
Type 1
출처 - http://tjjava.blogspot.kr/2012/06/enum.html
열거형 상수 (enum 타입) 정의 예제
파일명: Foo.java
enum Week { 월, 화, 수, 목, 금, 토, 일 } // 끝에 세미콜론(;)을 붙이지 않음
enum RGB { red, green, blue }
public static void main(String args []) {
// Week 이라는 새로운 자료형으로 Day 라는 변수를 만들어, "금"을 대입.
Week Day = Week.금;
System.out.println(Day + "요일"); // 출력 결과: 금요일
System.out.println(RGB.blue); // 출력 결과: blue
System.out.println(Week.토); // 출력 결과: 토
Day = Week.일;
System.out.println(Day); // 출력 결과: 일
}
}
열거형 상수 즉 Enumeration 이란, 미리 정해진 일정한 값을 가진 새로운 자료형을 사용자가 직접 만드는 것입니다.
문자열로 정의되어 있지만 내부적으로는 정수로 취급되기에, 일반 배열로 처리할 때보다 속도가 빠릅니다.
가령 일주일은 7개의 요일만 있고, 빛의 삼원색 (RGB) 은 3가지의 색으로만 이루어져 있기에, 이런 데이터를 다룰 때에는 열거형 상수로 정의하여 사용하면 이상적입니다.
상수이기에
Week.토 = Week.일;
이런 대입은 안됩니다. 그러면 Foo.java:12: cannot assign a value to final variable 토 이런 에러가 납니다.
enum 은 반드시 메소드 외부에서 정의해야 합니다. 그렇지 않으면 Foo.java:5: enum types must not be local 이런 에러가 납니다.
자바 버전 5.0 (=1.5) 이상에서만 Enumeration 이 지원됩니다.
출처 - http://mwultong.blogspot.com/2006/10/java-enum-enumeration.html
[번역]자바 Enum의 10가지 예제
원본글 : http://javarevisited.blogspot.sg/2011/08/enum-in-java-example-tutorial.html
자바의 Enumeration(Enum)은 JDK 1.5에 소개되었고, J2SE5에서 내가 가장 좋아하는
특징 중 하나이다.
타입처럼 Java Enum은 NEW,PARTIAL,FILL,FILL or CLOSED와 같은 주문의
대표적인 상태의 예와같이 확실한 상황하에서 더욱 적합하다.
Enumeration(Enum)은 원래 자바에서 이용하지 않았고, C나 C++같은 다른 언어에서
사용했다.
하지만 결국 자바는 깨닫게 되었고 enum keyword에 의해 JDK 5안에 Enum이 소개되었다.
이 Java enum 튜토리얼안에서 우리는 자바안의 다른 enum 예를 볼 수 있을 것이고
자바안의 enum 사용에 대해 배울 수 있다.
자바안에 Enum에 의해 공급된 다른 특징들과 그것들을 어떻게 사용해야 되는지가
이 Java enum 튜토리얼의 초점이 될 것이다.
만약 당신이 자바 enum을 불편하게 느끼지 않는 것보다 전의 C 혹은 C++에서
Enumeration을 사용하고 있다해도,자바안의 Enum에 대한 나의 의견은
어느 다른 언어보다도 더 다채롭고 다용도로 쓰일 것이다.
- Java enum 없이 어떻게 enumberable을 표현하는가
자바 enum이 자바 1.5로부터 사용된 이래로, 그것의 가치는 JDK1.5이전의 자바 안
enumerable value를 어떻게 보여주어서 사용할지 혹은 그것이 없이 사용할지에 대한
부분에 대해서 논의했다.
나는 behavior같은 enum을 모방해서 public static final 상수를 사용했다.
개념을 더욱 명확히 이해하기 위해 자바안의 enum 예제를 살펴보자
이 예제에서 우리는 PENNY (1) NICKLE (5), DIME (10), and QUARTER (25) 같이
값을 가지는 열거형처럼 US 통화코인을 사용할 것이다.
1 2 3 4 5 6 7 8 9 10 11 12 | class CurrencyDenom { public static final int PENNY = 1 ; public static final int NICKLE = 5 ; public static final int DIME = 10 ; public static final int QUARTER = 25 ; } class Currency { int currency; //CurrencyDenom.PENNY,CurrencyDenom.NICKLE, // CurrencyDenom.DIME,CurrencyDenom.QUARTER } |
이것이 우리의 목적을 어느정도 충족해주긴 하지만 몇가지 심각한 한계를 가지고 있다.
(1)No Type-Safety
모든것중에 첫번째는 타입에 대해 안전하지 않다는 것이다. 당신이 99 통화에 대해
어느 유효한 int value값을 할당하려 해도 저 값을 대표하는 coin이 없다.
(2) No Meaningful Printing
이 상수에 대한 어느것의 값을 출력하는 것은 당신이 “NICKLE “대신에 “5”를 출력할 때
코인의 의미있는 이름 대신에 그것의 numeric 값을 출력하게 될 것이다
(3) No namespace
currencyDenom 상수에 접근하기 위해 우리는 단지 PENNY를 사용하는 대신에
CurrencyDenom.PENNY 클래스이름을 고쳐서 사용할 필요가 있다.
이것은 또한 JDK 1.5안에서 static import를 사용함으로 이루어지게 되었다.
자바 enum은 이 모든 한계에 대한 대답이다. 자바의 enum은 타입에 대해 안전하고,
의미있는 String 이름을 부여하며 자신의 namaspace를 가지고 있다.
지금 위의 예제를 자바 enum을 사용해서 다시 보자.
1 | public enum Currency {PENNY, NICKLE, DIME, QUARTER}; |
여기 Currency는 우리의 enum이고 PENNY, NICKLE, DIME, QUARTER는 enum의 상수다.
enum상수 주변에 중괄호를 주목하라. 왜냐하면 enums는 자바의 클래스나 인터페이스
같은 타입이기 때문이다.
또한 우리는 클래스나 인터페이스처럼 enum을 위한 유사한 naming convention을 따를 것이고,
enum 상수들은 static final을 내재한 이후로 우리는 자바안의 상수처럼 그들을 표시하기 위해
모두 대문자로 사용한다.
- 자바안의 Enum은 무엇인가?
지금 “자바안의 enum은 무엇인가“에 대한 기본적인 질문으로 돌아가는 것이
자바의 키워드이며, 자바 enum에 대한 더욱 자세한 조항은 클래스나 인터페이스와 같은 타입이고
enum 상수로 정의해 사용할 수 있다.
enum 상수에 static과 final이 내재되어 있고, 당신은 한번 만들어지면 값을 바꿀 수 없다.
자바안의 Enum은 타입에 대해 안전하고 int 변수처럼 switch statement안에서 사용된다.
enum은 너가 변수 이름처럼 사용할 수 없는 키워드이며, JDK1.5에 소개된 이후로 너의 모든 이전 코드는
변수 이름과 같은 enum은 돌아가지 않을 것이고 리팩토링할 필요가 있을 것이다.
- 자바의 Enum에 대한 이익
1) Enum은 타입에 대해 안전하다. 당신은 미리 정의된 enum 변수안의 상수외 다른 것을 할당할 수 없다.
2) Enum은 그 자신의 name-space를 가진다.
3) Enum의 가장 큰 특징은 int나 char같이 원시타입처럼 switch statememt 안에서 Enum을 사용할 수 있다.
4) 자바의 Enum은 새로운 상수를 추가하기가 쉽고, 기존에 존재하는 코드를 고치지 않고 새로운 상수를 추가할
수 있다.
- 자바의 Enum에 대한 중요한 점
1) 자바안의 Enums는 타입에 대해 안전하고 자신의 name-space를 가진다. 그것은 enum이 type값을 가진다는 것이고
아래 “Currency” 예제에서 Enum 상수안에 명기된 것 외 어떤 다른 값도 할당할 수 없다
1 2 3 | public enum Currency {PENNY, NICKLE, DIME, QUARTER}; Currency coin = Currency.PENNY; coin = 1 ; //compilation error |
2) 지바안의 Enums는 클래스 혹은 인터페이스처럼 타입을 참조한다. 생성자를 정의할 수 있고, 자바 enum안의 메서드나 변수는
자바의 enum type의 다음 예제에서 보여준 것처럼 C나 C++안의 Enum보다 더욱 파워풀하게 만든다
3) 아래 예제에서 보는 것처럼 만들때 enum 상수에 값을 명기할 수 있다.
1 | public enum Currency {PENNY( 1 ), NICKLE( 5 ), DIME( 10 ), QUARTER( 25 )}; |
그러나 멤버변수나 생성자를 이용할 필요가 있을 때 이것을 해야한다. 왜냐하면 PENNY(1)은 정말로 아래 예제에서 보는 것처럼
int value를 가지는 생성자를 호출하기 때문이다.
1 2 3 4 5 6 7 8 | public enum Currency { PENNY( 1 ), NICKLE( 5 ), DIME( 10 ), QUARTER( 25 ); private int value; private Currency( int value) { this .value = value; } }; |
자바 enum의 생성자는 private이고, 다른 접근제어자는 에러가 나올 것이다. 지금 각 코인에 연결된 값을 가져오기 위해 어느 평범한
자바 클래스처럼 자바 enum안에 public getValue()메서드를 정의할 있다. 또한 첫번째 라인의 세미콜론은 선택이다.
4) Enum 상수들은 static과 final을 내재하고 한번 만들어지면 바꿀 수 없다. 아래 코드는 에러를 뱉어낼 것이다
1 2 | Currency.PENNY = Currency.DIME; The final field EnumExamples.Currency.PENNY cannot be re assigned. |
5) 자바의 Enum은 int, char처럼 switch statement의 인자로 사용할 수 있다. 이런 특징은 switch문에서
매우 유용하다. switch statement에서 java enum을 어떻게 사용하는지 아래 예를 보자
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Currency usCoin = Currency.DIME; switch (usCoin) { case PENNY: System.out.println( "Penny coin" ); break ; case NICKLE: System.out.println( "Nickle coin" ); break ; case DIME: System.out.println( "Dime coin" ); break ; case QUARTER: System.out.println( "Quarter coin" ); } |
6) enum안에 정의된 상수들은 final이고, 비교할때는 “==”를 사용한다.
1 2 3 4 5 | Currency usCoin = Currency.DIME; if (usCoin == Currency.DIME){ System.out.println( "enum in java can be" + "compared using ==" ); } |
7) 자바 컴파일러는 자동으로 모든 enum을 위한 static values() 메서드를 제공한다.
Values() 메서드는 enum 상수의 배열을 리턴한다. values()를 사용해서 enums의 값들을
배열을 돌면서 사용할 수 있다.
1 2 3 4 5 6 7 8 | for (Currency coin: Currency.values()){ System.out.println( "coin: " + coin); } And it will print: coin: PENNY coin: NICKLE coin: DIME coin: QUARTER |
enums안에 정의된 순서와 동일하다는 것에 주목하라
8) Enum은 메서드를 오버라이드 할 수 있다. 아래예제처럼 enum안에 toString()메서드를
오버라이드 해서 enums 상수들을 위한 의미있는 설명을 제공하고 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @Override public String toString() { switch ( this ) { case PENNY: System.out.println( "Penny: " + value); break ; case NICKLE: System.out.println( "Nickle: " + value); break ; case DIME: System.out.println( "Dime: " + value); break ; case QUARTER: System.out.println( "Quarter: " + value); } return super .toString(); } }; |
그리고 여기 그것이 어떻게 보여지는지 나와있다.
1 2 3 4 5 | Currency usCoin = Currency.DIME; System.out.println(usCoin); output: Dime: 10 |
9) 두개의 새로운 컬렉션 클래스 EnumMap과 EnumSet은 추가되었고, 자바 enum을 지원하기 위해 컬렉션
패키지에 추가되었다. 이러한 클래스들은 자바의 Map과 Set 인터페이스에서 높은 성능을 보이며 우리는
어떤 기회에서든지 이것을 사용할 수 있다
10) 자바의 new 연산자를 사용해서 객체를 생성할 수 없다. 왜냐하면 Enum의 생성자가 private이고
Enums 상수는 오직 Enums 그 자신 안에서는 만들어질 수 있다.
11) 자바 enums의 객체는 어떤 enums 상수가 코드안에서 처음 호출되거나 참조될 때 만들어진다.
12) 자바의 Enum은 인터페이스를 구현하고 평범한 클래스처럼 어느 메서드라도 오버라이드 할 수 있다.
그것은 또한 Serializable과 Comparable 인터페이스 둘다 구현을 내재하고 있다.
java enum을 사용하여 인터페이스를 어떻게 구현하는지 아래 예를 보자
1 2 3 4 5 6 7 8 9 10 11 | public enum Currency implements Runnable{ PENNY( 1 ), NICKLE( 5 ), DIME( 10 ), QUARTER( 25 ); private int value; ............ @Override public void run() { System.out.println( "Enum in Java implement interfaces" ); } } |
13) 자바의 enum안에 추상메서드도 정의할 수 있다. 또한 enum의 다른 객체를 위해 다른
구현을 제공할 수도 있다. 아래 enum안에 추상메서드를 사용한 예제를 보자
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | public enum Currency implements Runnable{ PENNY( 1 ) { @Override public String color() { return "copper" ; } }, NICKLE( 5 ) { @Override public String color() { return "bronze" ; } }, DIME( 10 ) { @Override public String color() { return "silver" ; } }, QUARTER( 25 ) { @Override public String color() { return "silver" ; } }; private int value; public abstract String color(); private Currency( int value) { this .value = value; } .............. } |
이번 예에서 모든 코인은 color() 추상메서드를 만들어 다른 컬러를 가지게 될 것이고, 자신의 컬러가
정의된 enum 객체를 가지게 될 것이다.
color()메서드를 호출해서 어느 코인의 컬러를 아래예처럼 가져올 수 있다.
1 | System.out.println( "Color: " + Currency.DIME.color()); |
- Enum valueof의 예
나의 구독자 중에 한명이 enum에서 String을 바꾸는valueOf메서드에 대해 언급되지 않았다는 걸 알려주었다.
여기 그가 제안한게 있다.
“enum의 valueOf()메서드를 포함할 수 있다. valueOf()는 static 메서드이고 String 인자값을 가지고
enum안에 String을 바꿔 사용할 수 있다.
한가지 생각해야 할건 enum의 valueOf(String)메서드는
“Exception in thread “main” java.lang.IllegalArgumentException: No enum const class
예외를 던질수 있다는 것이다.
ordenal()과 name() 유틸리티 메서드에 제안한 또 다른 독자는 Ordinal은 enum 상수의 포지션(순서)
를 리턴해주고, 특별한 enum 상수를 만들때 정확한 스트링을 리턴하도록 name()이 선언되어 있다라고 한다
*자바 enum의 대해선 아래 블로그에 정리가 잘 되어 있으니 참고하세요
출처 - http://bluepoet.me/2012/07/18/%EB%B2%88%EC%97%AD%EC%9E%90%EB%B0%94-enum%EC%9D%98-10%EA%B0%80%EC%A7%80-%EC%98%88%EC%A0%9C/
'Development > Java' 카테고리의 다른 글
java - jar (0) | 2012.11.09 |
---|---|
java 로드맵 (0) | 2012.11.07 |
java - @Override (0) | 2012.11.03 |
java - 문자열, 숫자, 영문 배열 및 list 정렬(sort) (0) | 2012.11.02 |
java - 클래스 구조 및 헬퍼 클래스(helper class) (0) | 2012.10.30 |