래퍼(wrapper)클래스
객체지향 개념에서 모든 것은 객체로 다루어져야 한다.
- Java에서는 8개의 기본형을 객체로 다루지 않는다. (완전한 객체지향 언어가 아니라는 얘기를 듣는 이유)
- 그 대신 보다 높은 성능을 얻을 수 있다.
기본형 변수도 어쩔 수 없이 객체로 다뤄야 할 경우?
- 매개변수로 객체를 요구할 때
- 기본형 값이 아닌 객체로 저장해야할 때
- 객체간의 비교가 필요할 때
- 등등~~_~~
기본형 값들을 객체로 변환하기 위해서는 래퍼(wrapper)클래스를 사용해야 한다.
- 래퍼 클래스들은 객체생성 시에 생성자의 인자로 주어진 각 자료형에 알맞은 값을 내부적으로 저장하고 있다.
기본형 | 래퍼클래스 | 생성자 |
boolean | Boolean | Boolean(boolean value) Boolean(String s) |
char | Character | Character(char value) |
byte | Byte | Byte(byte value) Byte(String s) |
short | Short | Short(short value) Short(String s) |
int | Integer | Integer(int value) Integer(String s) |
long | Long | Long(long value) Long(String s) |
float | Float | Float(double value) Float(float value) Float(String s) |
double | Double | Double(double value) Double(String s) |
매개변수로 문자열을 제공할 때, 각 자료형에 알맞은 문자열을 사용해야 한다.
- ‘new Integer(”1.0”);’과 같이 하면 NumberFormatException 발생 (new Double에서 상관없음)
래퍼 클래스들은 모두 equals()가 오버라이딩되어 있어서 주소값이 아닌 객체가 가지고 있는 값을 비교한다.
- toString()도 오버라이딩되어 있어서 객체가 가지고 있는 값을 문자열로 변환하여 반환한다.
래퍼 클래스들은 MAX_VALUE, MIN_VALUE, SIZE, BYTES, TYPE등의 static상수를 공통적으로 가지고 있다.
오토박싱이 된다고 해도 Integer객체에 비교연산자를 사용할 수 없다. 대신 compareTo() 제공한다.
Double in = new Double("1.0");
Double in1 = new Double("1.0");
System.out.println(in < in1); //false
문자열과 기본형 간의 변화에서도 사용된다.
문자열 → 숫자 방법 (반환 타입만 다르지 같은 메서드다.)
int i1 = Integer.parseInt(str1); //방법1
int i2 = Integer.valueOf(str1); //방법2
valueOf()의 반환 타입은 int가 아니라 Integer인데 오토박싱(auto-boxing)에 의해 Interger가 int로 자동변환 한다.
오토박싱 설명은 밑에 있습니다.
💡 byte,short를 문자열로 변경할 때는 String valueOf(int i)를 사용
숫자 → 문자열
public static void main(String[] args) {
int i = 1999;
String str1 = i + "";
String str2 = String.valueOf(i);
System.out.println("str1 = " + str1);
System.out.println("str2 = " + str2);
}
/*
str1 = 1999 방법1
str2 = 1999 방법2
*/
성능은 valueof()가 더 좋지만, 빈문자열을 더하는 방법이 간단하고 편하기 때문에 성능향상 필요할 때만 valueOf()사용하자
💡 참조변수에 String을 더하면, 참조변수가 가리키는 인스턴스 toString()을 호출하여 String을 얻은 다음 결합한다.
문자열과 기본형 간의 변환
public static void main(String[] args) {
int iVal = 100;
String strIVal = String.valueOf(iVal); //int 100
double dVal = 200.0;
String strDVal = dVal + ""; //String 으로 변환하는 다른 방법
double sum1 = Integer.parseInt("+"+strIVal.trim()) +
Double.parseDouble(strDVal.trim());
double sum2 = Integer.valueOf(strIVal) + Double.valueOf(strDVal);
System.out.println("sum1 = " + sum1);
System.out.println("sum2 = " + sum2);
}
parseInt()나 ParseFloat()같은 메서드는 문자열 공백 또는 문자가 포함되어 있는 경우 변환 시 예외(NumberFormatException)이 발생될 수 있다.
String value = "100 ";
int i1 = new Integer(value.trim()).intValue(); //floatValue(), longValue(),..
int i2 = Integer.parseInt(value.trim()); // 주로 이방법 많이 사용
Integer i3 = Integer.valueOf(value.trim());
- 문자열 양끝의 공백을 제거해주는 trim()을 습관적으로 같이 사용하자.
- 부호를 의미하는 ‘+’ 소수점을 의미하는 ‘ . ‘ 각 자료형의 접미사(f, L)는 허용된다.
- 자료형에 알맞은 변환을 하는 경우에만 허용된다.
‘타입.parse타입(String s)’ → 반환값이 기본형
‘타입.valueOf(String s)’ → 반환값이 래퍼 클래스 타입
- 문자열을 숫자로 변환하는 과정에서는 예외가 발생하기 쉽기 때문에 주의하고 예외가 발생했을 때의 처리를 적절하게 해주어야 한다.
문자열이 10진수가 아닌 다른 진법(radix)의 숫자일 때도 변환이 가능하도록 메서드가 제공된다.
Integer클래스의 static int parseInt(String s, int radix)를 사용하면 16진수 값으로 표현된 문자열도 변환할 수 있다.
static int parseInt(String s, int radix) //문자열 s를 radix진법으로 인식
static Integer valueOf(String s, int radix)
16진법에서는 ‘A~F’의 문자도 허용한다.
- 따라서 대소문자 구별 없이 a,b,c,d,e,f 도 사용 가능하다.
- int result = Integer.*parseInt*("a",16); result에는 정수값 10이 저장된다.
int i1 = Integer.parseInt(value.trim(),16); //FF(16) -> 255
// int i2 = Integer.parseInt(value.trim()); -> NumberFormatException발생
// int i3 = Integer.valueOf(value.trim()); -> NumberFormatException발생
진법을 생략하면 10진수로 간주하기 때문에 진법을 생략하면 NumberFormatException이 발생한다.
Number클래스
추상클래스로 내부적으로 숫자를 멤버변수로 갖는 래퍼 클래스들의 부모이다.
래퍼클래스의 상속계층도이다.
- 기본형 중에서 숫자와 관련된 래퍼클래스들은 모두 Number클래스의 자식이다.
BigInteger : long으로도 다룰 수 없는 큰 범위의 정수를 처리하기 위한 것
BigDecimal : double로도 다룰 수 없는 큰 범위의 부동 소수점수를 처리하기 위한 것
둘다 연산자의 역활을 대신하는 다양한 메서드를 제공한다.
Number클래스의 실제소스
package java.lang;
public abstract class Number implements java.io.Serializable {
public abstract int intValue();
public abstract long longValue();
public abstract float floatValue();
public abstract double doubleValue();
public byte byteValue() {
return (byte)intValue();
}
public short shortValue() {
return (short)intValue();
}
}
객체가 가지고 있는 값을 숫자와 관련된 기본형으로 변환하여 반환하는 메서드들을 정의하고 있다.
오토박싱 & 언박싱
기본형 값을 래퍼 클래스의 객체로 자동 변환해주는 것을 '오토박싱(autoboxing)'
래퍼 클래스의 객체를 기본형 값으로 자동 변환해주는 것을 '언박싱(unboxing)'
JDK1.5 이전에는 기본형과 참조형 간의 연산이 불가능했기 때문에, 래퍼 클래스로 기본형을 객체로 만들어 연산해야 했다.
- 이제는 기본형과 참조형간의 연산이 가능하다.
- 컴파일러가 자동으로 변환하는 코드를 넣어주기 때문에 가능함
컴파일 전의 코드 | 컴파일 후의 코드 |
int i = 5; Integer iObj = new Integer(7); int sum = i + iObj; |
int i = 5; Integer iObj = new Integer(7); int sum = i + iObj.intValue(); |
내부적으로 객체 배열을 가지고 있는 Vector클래스나 ArrayList클래스에 기본형 값을 저장해야할 때나 형변환이 필요할 때도 컴파일러가 자동적으로 코드를 추가해준다.
int i = 10;
// 기본형을 참조형으로 형변환(형변환 생략가능)
Integer intg = (Integer)i; // Integer.valueOf(i);
Object obj = (Object)i; // (Object)Integer.valueOf(i);
Long lng = 100L; // new Long(100L);
//참조형을 기본형으로 형변환도 가능(형변환 생략가능)
int i2 = (int)intg; //참조형을 기본형으로
컴파일러가 제공하는 편리한 기능일 뿐 자바의 원칙이 바뀐것이 아니다.
- 기본형과 참조형 혹은 참조형 간의 연산이 가능한 이유
- 참조형과 기본형 간의 형변환이 가능한 이유(형변환 생략가능)
💡 기본형 ↔ 래퍼 클래스의 객체 변환을 자동으로 컴파일러가 지원해주기 때문에 편하다.
'책 > Java의 정석' 카테고리의 다른 글
Optional<T> (0) | 2023.03.24 |
---|---|
[java] Object클래스 (0) | 2023.02.09 |
[java] String 클래스와 StringBuffer (0) | 2023.02.09 |
[java] 예외처리(3) (0) | 2023.02.07 |
[java] 예외처리(2) (0) | 2023.02.07 |