Language/Java

β˜• μžλ°” Wrapper ν΄λž˜μŠ€μ™€ Boxing & UnBoxing 총정리

인파_ 2022. 11. 14. 13:26

java-boxing-unboxing

래퍼 클래슀 (Wrapper Class)

이전 κ°•μ˜κΈ€μ—μ„œ μš°λ¦¬λŠ” μžλ°”μ˜ μžλ£Œν˜•μ€ κΈ°λ³Έ νƒ€μž…(primitive type)κ³Ό μ°Έμ‘° νƒ€μž…(reference type) μœΌλ‘œ λ‚˜λˆ„μ–΄μ§€κ³  각 νŠΉμ§•μ— λŒ€ν•΄ μ•Œμ•„λ³΄μ•˜λ‹€.

ν”„λ‘œκ·Έλž˜λ°μ„ ν•˜λ‹€ 보면 κΈ°λ³Έ νƒ€μž…μ˜ 데이터λ₯Ό 객체둜 ν‘œν˜„ν•΄μ•Ό ν•˜λŠ” κ²½μš°κ°€ μ’…μ’… μƒκΈ°κ²Œ λœλ‹€.

예λ₯Ό λ“€μ–΄ λ©”μ†Œλ“œμ˜ 인수둜 객체 νƒ€μž…λ§Œμ΄ μš”κ΅¬λ˜λ©΄, κΈ°λ³Έ νƒ€μž…μ˜ 데이터λ₯Ό κ·ΈλŒ€λ‘œ μ‚¬μš©ν• μˆ˜ μ—†κΈ° λ•Œλ¬Έμ— μ–΄λ– ν•œ λ³€ν™˜ μž‘μ—…μ΄ ν•„μš”ν•΄ 진닀.

λ˜ν•œ λ©€ν‹°μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œ 동기화 데이터λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•  경우 이λ₯Ό 객체화 ν•΄μ•Ό ν•  ν•„μš”μ„±μ΄ 생긴닀.

 

이럴 λ•Œμ— κΈ°λ³Έ νƒ€μž…(primitive type)을 객체둜 닀루기 μœ„ν•΄μ„œ μ‚¬μš©ν•˜λŠ” ν΄λž˜μŠ€λ“€μ„ 래퍼 클래슀(wrapper class)라고 ν•œλ‹€. 

μžλ°”λŠ” λͺ¨λ“  κΈ°λ³Ένƒ€μž…(primitive type)은 값을 κ°–λŠ” 객체λ₯Ό 생성할 수 μžˆλ‹€.

이런 객체λ₯Ό 포μž₯ 객체라고도 ν•˜λŠ”λ°, κΈ°λ³Έ νƒ€μž…μ˜ 값을 내뢀에 두고 포μž₯ν•˜λŠ” κ²ƒμ²˜λŸΌ 보이기 λ•Œλ¬Έμ΄λ‹€.

포μž₯된 물건을 λ°”κΏ€μˆ˜ 없듯이, 래퍼 클래슀둜 감싸고 μžˆλŠ” κΈ°λ³Έ νƒ€μž… 값은 μ™ΈλΆ€μ—μ„œ λ³€κ²½ν•  수 μ—†λ‹€.

λ§Œμ•½ 값을 λ³€κ²½ν•˜κ³  μ‹Άλ‹€λ©΄ μƒˆλ‘œμš΄ 포μž₯ 객체λ₯Ό λ§Œλ“€μ–΄μ•Ό ν•œλ‹€.

 

래퍼 ν΄λž˜μŠ€λŠ” λͺ¨λ‘ java.lang νŒ¨ν‚€μ§€μ— ν¬ν•¨λ˜μ–΄ μ œκ³΅λœλ‹€.

κ·Έλž˜μ„œ λ³„λ‹€λ₯Έ νŒ¨ν‚€μ§€ 뢈러였기 없이 κ³§λ°”λ‘œ μ†ŒμŠ€ λ‹¨μ—μ„œ μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€.

래퍼 클래슀λ₯Ό μ΄μš©ν•˜λ©΄ 각 νƒ€μž…μ— ν•΄λ‹Ήν•˜λŠ” 데이터λ₯Ό νŒŒλΌλ―Έν„°λ‘œ 전달받아 ν•΄λ‹Ή 값을 κ°€μ§€λŠ” 객체둜 λ§Œλ“€μ–΄μ€€λ‹€.

java-Wrapper-Class

Integer num1 = new Integer(5); // κΈ°λ³Έν˜• νƒ€μž… μ •μˆ˜λ₯Ό 래퍼 클래슀둜 감싸 객체화
Integer num1 = 5; // μ΄λŸ°μ‹μœΌλ‘œλ„ ν‘œν˜„ κ°€λŠ₯

Double num2 = new Double(1.11); // κΈ°λ³Έν˜• νƒ€μž… μ‹€μˆ˜λ₯Ό 래퍼 클래슀둜 감싸 객체화
Double num2 = 1.11;

 

μžλ°”μ˜ 8개의 κΈ°λ³Έ νƒ€μž…μ— λŒ€ν•œ 래퍼 ν΄λž˜μŠ€λŠ” λ‹€μŒκ³Ό κ°™λ‹€.

κΈ°λ³Έ νƒ€μž… 래퍼 클래슀
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
λŒ€λΆ€λΆ„μ˜ 래퍼 ν΄λž˜μŠ€λŠ” κΈ°λ³Έ νƒ€μž…μ˜ 첫 번째 단어λ₯Ό λŒ€λ¬Έμžλ‘œ λ°”κΏ”μ€€ μ΄λ¦„μœΌλ‘œ λ˜μ–΄μžˆμ§€λ§Œ, 이 μ€‘μ—μ„œ Integer 와 Character 클래슀만이 μžμ‹ μ˜ κΈ°λ³Έ νƒ€μž…κ³Ό 이름이 μ•½κ°„ λ‹€λ₯΄λ‹€λŠ” 점은 μœ μ˜ν•˜μž.

λ°•μ‹±(Boxing) & μ–Έλ°•μ‹±(UnBoxing)

java-boxing-unboxing

μœ„μ—μ„œ 래퍼 ν΄λž˜μŠ€λŠ” 값을 포μž₯ν•˜μ—¬ 객체둜 λ§Œλ“œλŠ” 것이라고 ν–ˆλ‹€.

값을 포μž₯ν•˜μ—¬ 객체둜 λ§Œλ“œλŠ” 것 κΉŒμ§€λŠ” μ’‹μ§€λ§Œ, 만일 값을 λ”ν•˜κ±°λ‚˜ λ“± λ³€ν™˜μ‹œμΌœμ•Ό ν•  ν•„μš”κ°€ 생길 경우 포μž₯을 λ‹€μ‹œ λœ―μ„ ν•„μš”κ°€ μžˆλ‹€.

μ΄λŸ¬ν•œ ν–‰μœ„λ₯Ό 전문적인 μš©μ–΄λ‘œ λ§ν•˜μžλ©΄, λ°•μ‹±(Boxing) κ³Ό μ–Έλ°•μ‹±(UnBoxing) 이라고 ν•œλ‹€.

  • Boxing : κΈ°λ³Έ νƒ€μž…μ˜ 데이터 → 래퍼 클래슀의 μΈμŠ€ν„΄μŠ€λ‘œ λ³€ν™˜
  • UnBoxing : 래퍼 클래슀의 μΈμŠ€ν„΄μŠ€μ— μ €μž₯된 κ°’ → κΈ°λ³Έ νƒ€μž…μ˜ λ°μ΄ν„°λ‘œ λ³€ν™˜
래퍼 ν΄λž˜μŠ€λŠ” μ‚°μˆ  연살을 μœ„ν•΄ μ •μ˜λœ ν΄λž˜μŠ€κ°€ μ•„λ‹ˆλ‹€.
μƒμ„±λœ μΈμŠ€ν„΄μŠ€μ˜ κ°’λ§Œμ„ μ°Έμ‘°ν• μˆ˜ 있기 λ•Œλ¬Έμ— λ”°λΌμ„œ 래퍼 클래슀 μΈμŠ€ν„΄μŠ€μ— μ €μž₯된 값을 직접 변경이 λΆˆκ°€λŠ₯ν•˜λ‹€.
κ·Έλž˜μ„œ 래퍼 클래슀λ₯Ό μ–Έλ°•μ‹± ν•œ 뒀에 값을 λ³€κ²½ν•œ λ’€ λ°•μ‹±ν•΄μ•Ό ν•˜λŠ” 쀑간 단계λ₯Ό κ±°μΉ  ν•„μš”κ°€ μžˆλ‹€.
// λ°•μ‹±
Integer num = new Integer(20); // Integer 래퍼 클래슀 num 에 21 의 값을 μ €μž₯

// μ–Έλ°•μ‹± (intValue)
int n = num.intValue(); // 래퍼 클래슀 num 의 값을 κΊΌλ‚΄ κ°€μ Έμ˜¨λ‹€.

// 재 포μž₯(λ°•μ‹±)
n = n + 100; // 120
num = new Integer(n);

각 Wrapper νƒ€μž…μ˜ 클래슀의 μ–Έλ°•μ‹± λ©”μ†Œλ“œλ“€ λ‹€μŒκ³Ό κ°™λ‹€.

 λ©”μ†Œλ“œ λ°˜ν™˜κ°’  μ„€λͺ… 
booleanValue() boolean  κΈ°λ³Έν˜• 데이터λ₯Ό λ¬Έμžμ—΄λ‘œ λ°”κΎΌ 뒀에 λ°˜ν™˜ 
byteValue() byte  객체의 값을 byte κ°’μœΌλ‘œ λ³€ν™˜ν•˜μ—¬ λ°˜ν™˜ 
doubleValue()  double  객체의 값을 double κ°’μœΌλ‘œ λ³€ν™˜ν•˜μ—¬ λ°˜ν™˜ 
floatValue()  float 객체의 값을 float κ°’μœΌλ‘œ λ³€ν™˜ν•˜μ—¬ λ°˜ν™˜ 
intValue()  int  객체의 값을 int κ°’μœΌλ‘œ λ³€ν™˜ν•˜μ—¬ λ°˜ν™˜ 
longValue()  long  객체의 값을 long κ°’μœΌλ‘œ λ³€ν™˜ν•˜μ—¬ λ°˜ν™˜ 
shortValue() short  객체의 값을 short κ°’μœΌλ‘œ λ³€ν™˜ν•˜μ—¬ λ°˜ν™˜ 

μžλ™ λ°•μ‹±(AutoBoxing) & μžλ™ μ–Έλ°•μ‹±(AutoUnBoxing)

JDK 1.5 λΆ€ν„°λŠ” λ°•μ‹±κ³Ό 언박싱이 ν•„μš”ν•œ 상황에 μžλ°” μ»΄νŒŒμΌλŸ¬κ°€ μžλ™μœΌλ‘œ μ²˜λ¦¬ν•΄μ£ΌκΈ° μ‹œμž‘ν–ˆλ‹€.
μ΄λŸ¬ν•œ μžλ™ν™”λœ λ°•μ‹±κ³Ό 언박싱을 μ˜€ν† λ°•μ‹± (AutoBoxing) κ³Ό  μ˜€ν† μ–Έλ°•μ‹± (AutoUnBoxing) 이라고 λΆ€λ₯Έλ‹€.

κΈ°λ³Ένƒ€μž… 값을 직접 λ°•μ‹±, μ–Έλ°•μ‹±ν•˜μ§€ μ•Šμ•„λ„ 래퍼 클래슀 λ³€μˆ˜μ— λŒ€μž…λ§Œ ν•˜λ©΄ μžλ™μœΌλ‘œ λ°•μ‹±κ³Ό 언박싱이 λœλ‹€.

/* κΈ°μ‘΄ λ°•μ‹± & μ–Έλ°•μ‹± */
Integer num = new Integer(17); // λ°•μ‹±
int n = num.intValue();        // μ–Έλ°•μ‹±

/* μ˜€ν†  λ°•μ‹± & μ–Έλ°•μ‹± */
Integer num = 17; // new Integer() μƒλž΅
int n = num; // intValue() μƒλž΅

이처럼 μ˜€ν†  박싱을 μ΄μš©ν•˜λ©΄ new ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³ λ„ μžλ™μœΌλ‘œ μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 수 있으며, μ–Έλ°•μ‹± λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³ λ„, μ˜€ν†  언박싱을 μ΄μš©ν•˜μ—¬ μΈμŠ€ν„΄μŠ€μ— μ €μž₯된 값을 λ°”λ‘œ μ°Έμ‘°ν•  수 있게 λœλ‹€.

 

래퍼 클래슀 μ—°μ‚°

μ˜€ν†  λ°•μ‹± & μ–Έλ°•μ‹± κΈ°λŠ₯을 μ΄μš©ν•΄ λ‹€μŒκ³Ό 같이 래퍼 객체λ₯Ό 직접 연산이 κ°€λŠ₯ν•΄μ§€κ²Œ λœλ‹€.

μ›λž˜λŠ” 래퍼 ν΄λž˜μŠ€λŠ” 직접 연산이 λΆˆκ°€λŠ₯ ν•˜μ§€λ§Œ μ»΄νŒŒμΌλŸ¬κ°€ 슀슀둜 νŒλ‹¨ν•΄ μžλ™μœΌλ‘œ μ–Έλ°•μ‹±ν•˜μ—¬ μ—°μ‚° ν•˜κΈ° λ•Œλ¬Έμ— λ‹€μŒ ꡬ문이 ν—ˆμš©λ˜λŠ” 것이닀.

Integer num1 = new Integer(7); // λ°•μ‹±
Integer num2 = new Integer(3); // λ°•μ‹±

int int1 = num1.intValue();    // μ–Έλ°•μ‹±
int int2 = num2.intValue();    // μ–Έλ°•μ‹±

// λ°•μ‹±λœ 객체λ₯Ό μ˜€ν†  μ–Έλ°•μ‹±ν•˜μ—¬ μ—°μ‚°ν•˜κ³  λ‹€μ‹œ λ°•μ‹±ν•˜μ—¬ μ €μž₯
Integer result1 = num1 + num2; // 10 
Integer result2 = int1 - int2; // 4
int result3 = num1 * int2;     // 21
[ NullPointException μ—λŸ¬ ]

래퍼 객체λ₯Ό λ‹€λ£°λ•Œ κ°€μž₯ 많이 보게 될 μ—λŸ¬ μ˜ˆμ™Έ 메세지 일 것이닀.
null 값을 κ°€μ§€λŠ” wrapper 클래슀 객체와 κΈ°λ³Έν˜•(primitive type) 값을 μ—°μ‚°ν•  경우, NullPointException이 λ°œμƒν•˜κ²Œ λœλ‹€.
μ΄λŠ” ν”Όμ—°μ‚°μžμ— κΈ°λ³Έν˜• int 값이 μ‘΄μž¬ν•˜μ—¬ wrapper 클래슀 객체λ₯Ό auto unboxing ν•˜λŠ” 쀑에 λ°œμƒν•˜λŠ” μ—λŸ¬μ΄λ‹€.
NullPointException

 

래퍼 클래슀 동등 비ꡐ

μ˜€ν†  언박싱을 톡해 객체 값을 λ”ν•˜κ³  λΉΌκ³ λŠ” λ¬Έμ œλŠ” μ—†μ§€λ§Œ, 객체 값을 비ꡐλ₯Ό ν• λ•ŒλŠ” 쑰심해야 ν•œλ‹€.

μΈμŠ€ν„΄μŠ€μ— μ €μž₯된 값에 λŒ€ν•œ 동등 μ—¬λΆ€ νŒλ‹¨μ€ 동등 μ—°μ‚°μž == μœΌλ‘œλŠ” 값을 λΉ„κ΅ν•˜λŠ”κ²Œ μ•„λ‹Œ 객체의 μ£Όμ†Œκ°’μ„ λΉ„κ΅ν•΄μ„œ μ˜λ„μ μ΄μ§€ μ•Šμ€ μž‘λ™μ΄ μΌμ–΄λ‚˜κΈ° λ•Œλ¬Έμ΄λ‹€.

Integer num1 = new Integer(100);
Integer num2 = new Integer(100);

num1 == num2; // μ°Έμ‘°ν˜•κ³Ό μ°Έμ‘°ν˜• 비ꡐ false

 

λ”°λΌμ„œ 래퍼 클래슀의 객체 κ°’ λΉ„κ΅λŠ” 포μž₯ λ‚΄λΆ€μ˜ 값을 μ–»μ–΄ 비ꡐ해야 되기 λ•Œλ¬Έμ—, 직접 μ–Έλ°•μ‹±ν•΄μ„œ λΉ„κ΅ν•˜λ˜κ°€, equals() λ©”μ†Œλ“œλ₯Ό 톡해 λ°”λ‘œ 비ꡐ가 κ°€λŠ₯ν•˜λ‹€.

Integer num1 = new Integer(10);
Integer num2 = new Integer(20);
Integer num3 = new Integer(10);

System.out.println(num1 == num3);      // false
System.out.println(num1.equals(num3)); // true

// 동등 비ꡐ μ™Έμ˜ 연산은 문제 μ—†λ‹€.
System.out.println(num1 < num2);       // true
System.out.println(num1 + num2);       // 30

 

λŒ€μ‹  래퍼 ν΄λž˜μŠ€μ™€ κΈ°λ³Έ μžλ£Œν˜•κ³Όμ˜ λΉ„κ΅λŠ” μžλ™μœΌλ‘œ μ˜€ν† λ°•μ‹±κ³Ό 언박싱을 ν•΄μ£ΌκΈ° λ•Œλ¬Έμ— == μ—°μ‚°κ³Ό equals μ—°μ‚° λͺ¨λ‘ κ°€λŠ₯ν•˜λ‹€.

Integer num = new Integer(10); // 래퍼 클래슀1
Integer num2 = new Integer(10); // 래퍼 클래슀2
int i = 10; // κΈ°λ³Ένƒ€μž…

// 래퍼클래슀 == κΈ°λ³Ένƒ€μž…
System.out.println(num == i); // true

// 래퍼클래슀.equals(κΈ°λ³Ένƒ€μž…)
System.out.println(num.equals(i)); // true

// 래퍼클래슀 == 래퍼클래슀
System.out.println(num == num2); // false (invalid)

// 래퍼클래슀.equals(래퍼클래슀)
System.out.println(num.equals(num2)); // true

μžλ£Œν˜• λ³€ν™˜ λ©”μ†Œλ“œ

객체λ₯Ό 포μž₯ν•˜λŠ” κΈ°λŠ₯ 외에도, 래퍼 ν΄λž˜μŠ€λŠ” 자체 μ§€μ›ν•˜λŠ” parseνƒ€μž…() λ©”μ†Œλ“œλ₯Ό μ΄μš©ν•˜μ—¬ 데이터 νƒ€μž…μ„ ν˜• λ³€ν™˜ ν• λ•Œλ„ 유용히 쓰인닀.

String str = "10";
String str2 = "10.5";
String str3 = "true";

byte b = Byte.parseByte(str);
int i = Integer.parseInt(str);
short s = Short.parseShort(str);
long l = Long.parseLong(str);
float f = Float.parseFloat(str2);
double d = Double.parseDouble(str2);
boolean bool = Boolean.parseBoolean(str3);

System.out.println("λ¬Έμžμ—΄ byteκ°’ λ³€ν™˜ : "+b);
System.out.println("λ¬Έμžμ—΄ intκ°’ λ³€ν™˜ : "+i);
System.out.println("λ¬Έμžμ—΄ shortκ°’ λ³€ν™˜ : "+s);
System.out.println("λ¬Έμžμ—΄ longκ°’ λ³€ν™˜ : "+l);
System.out.println("λ¬Έμžμ—΄ floatκ°’ λ³€ν™˜ : "+f);
System.out.println("λ¬Έμžμ—΄ doubleκ°’ λ³€ν™˜ : "+d);
System.out.println("λ¬Έμžμ—΄ booleanκ°’ λ³€ν™˜ : "+bool);

Boxing & Unboxing μ„±λŠ₯ κ³ λ €

κΈ°λŠ₯적 νŽΈμ˜μ„±μ„ μœ„ν•˜μ—¬ μ˜€ν†  λ°•μ‹± / 언박싱을 μ œκ³΅ν•˜μ§€λ§Œ, λ‹€λ₯Έ νƒ€μž…κ°„μ˜ ν˜• λ³€ν™˜μ€ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ„±λŠ₯에 영ν–₯을 미치게 λœλ‹€. 비둝 μ‚¬μ†Œν•œ 차이 일지라도 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ„±λŠ₯ μΈ‘λ©΄μ—μ„œ λ΄€μ„λ•Œ λ°˜λ“œμ‹œ ν•„μš”ν•œ 상황이 μ•„λ‹ˆλΌλ©΄ 지양 ν•΄μ•Ό ν•˜λŠ” 것이 μ˜³λ‹€.

이해λ₯Ό λ•κΈ°μœ„ν•΄ 100만 건의 데이터λ₯Ό λ‹€λ£¨λŠ” 예제λ₯Ό 듀어보겠닀.

 

Auto Boxing을 ν¬ν•¨ν•œ μ—°μ‚°

public static void main(String[] args) {
  long t = System.currentTimeMillis(); // ν˜„μž¬ μ‹œκ°„(λ°€λ¦¬μ΄ˆ)λ₯Ό μ €μž₯
  
  Long sum = 0L; // 래퍼 객체둜 μ˜€ν†  λ°•μ‹±μœΌλ‘œ μ •μˆ˜ 값을 μ €μž₯
  
  // 백만번 λ„λŠ” λ™μ•ˆ λ”ν•˜κΈ° μ—°μ‚°
  for (long i = 0; i < 1000000; i++) {
  	sum += i;
  }
  
  System.out.println("processing time: " + (System.currentTimeMillis() - t) + " ms") ;
}
processing time: 34 ms

 

primitive νƒ€μž…κ°„ μ—°μ‚°

public static void main(String[] args) {
    long t = System.currentTimeMillis();
    
    long sum = 0L; // κΈ°λ³Έν˜• μ •μˆ˜ νƒ€μž…μΈ long μžλ£Œν˜•μ— μ •μˆ˜ μ €μž₯
    
    for (long i = 0; i < 1000000; i++) {
        sum += i;
    }
    
    System.out.println("processing time: " + (System.currentTimeMillis() - t) + " ms") ;
}
processing time: 5 ms

 

μœ„μ™€ 같이 총 100만번의 sum 연산을 톡해 두 μ½”λ“œμ˜ κ²°κ³Όλ₯Ό 비ꡐ해 보면, 거의 5배의 κ²°κ³Ό 차이λ₯Ό 보여쀀닀.

만일 μ‹€μ œλ‘œ λŒ€μš©λŸ‰ νŠΈλž˜ν”½μ΄ λ°œμƒν•˜λŠ” μ„œλΉ„μŠ€λ₯Ό μ΄μš©ν•  경우 100λ§Œκ±΄μ„ λ„˜μ–΄ 1000만건, 1μ–΅κ±΄μ˜ μ²˜λ¦¬κ°€ ν•„μš”ν• μ§€λ„ λͺ¨λ₯΄κ³ , 단지 λ˜‘κ°™μ€ μžλ£Œκ°’μ„ μ €μž₯ν•˜μ§€λ§Œ μ–΄λ–€ νƒ€μž… λ°©μ‹μœΌλ‘œ μ„ μ–Έν–ˆλŠλƒμ— 따라 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ μ„±λŠ₯ μ°¨μ΄λŠ” 점점 λ²Œμ–΄μ§€κ²Œ 될 것이닀.

Boxing & Unboxing

λ”°λΌμ„œ μž‘μ„±ν•œ μ½”λ“œμ— λΆˆν•„μš”ν•œ auto casting이 반볡적으둜 이루어지고 μžˆλŠ”μ§€ ν™•μΈν•˜λŠ” 것은 λŒ€μš©λŸ‰ μ„œλΉ„μŠ€λ₯Ό κ°œλ°œν•˜λŠ”λ° μžˆμ–΄μ„œ 꼼꼼히 νŒŒμ•…ν•΄μ•Όν•˜λŠ” μš”μ†Œμ΄λ‹€.


# 참고자료

http://www.tcpschool.com/java/java_api_wrapper