자바에서 간단한 계산을 할 때에는 대부분 기본 자료형(Primitive Type)을 사용한다. 이 기본 자료형은 자바의 힙(Heap)이라는 영역에 저장되지 않고, 스택
이라는 영역에 저장되어 관리된다. 따라서, 계산을 할 때 보다 빠른 처리가 가능하다.
그런데, 이러한 기본 자료형의 숫자를 객체
로 처리해야 할 필요가 있을 수도 있다. 따라서, 자바에는 다음과 같이 기본 자료형으로 선언되어 있는 타입의 클래스들이 선언되어 있다.
Character 클래스를 제외하고 나머지 클래스들은 각 기본 자료형의 이름에서 첫 문자만 대문자로 바뀌었다고 보면 된다. 그런데, Character와 Boolean을 제외한 숫자를 처리하는 클래스들은 감싼 클래스(Wrapper) 클래스
라고 불리며, 모두 Number
라는 abstract 클래스를 확장(extends) 한다. 그리고 겉으로 보기에는 참조 자료형이지만, 기본 자료형처럼 사용할 수 있다. 왜나하면, 자바 컴파일러에서 자동으로 형 변환을 해주기 때문이다.
그리고 Character 클래스를 제외하고는 공통적인 메소드를 제공한다. 바로 parse타입이름() 메소드
와 valueOf()
라는 메소드다.
예제 코드
package lang;
public class JavaLangNumber {
public static void main(String[] args){
JavaLangNumber sample = new JavaLangNumber();
sample.numberTypeCheck();
}
public void numberTypeCheck(){
String value1 = "3";
String value2 = "5";
byte byte1 = Byte.parseByte(value1);
byte byte2 = Byte.parseByte(value2);
System.out.println(byte1 + byte2);
Integer refInt1 = Integer.valueOf(value1);
Integer refInt2 = Integer.valueOf(value2);
System.out.println(refInt1 + refInt2 + "7");
}
}
코드를 보면 알겠지만, 이 두 가지 메소드는 모두 static 메소드다. 따라서, 타입의 객체를 생성할 필요 없이 바로 사용할 수 있다. 둘 다 String과 같은 문자열을 숫자 타입으로 변환한다는 공통점이 있지만, parse타입() 메소드는 기본 자료형을 리턴하고, valueOf() 메소드는 참조 자료형을 리턴한다.
실행 결과
첫 번째 결과가 byte 타입을 더한 것이니까 8로 출력되는 것은 모두 쉽게 이해할 것이다. 그런데, 두 번째 결과가 87로 나온 것은 조금 이해하기 힘들 것이다. 왜냐하면, 참조 자료형은 두 값을 더할 수 없는데 숫자 연산이 된 8이라는 값이 출력되고, "7"이 그 뒤에 붙었기 때문이다.
참조 자료형 중에 더하기 연산이 가능한 것은 String 뿐이다. 그런데, 참조 자료형 중에서 Byte, Short, Integer, Long, Float, Double 타입들은 필요시 기본 자료형처럼 사용할 수 있다. 따라서 new를 사용하여 객체를 만들지 않아도 값을 할당할 수 있다. 즉, 다음과 같이 사용하는 것도 전혀 문제되지 않는다.
public void numberTypeCheck2() {
Integer refInt1;
refInt1 = 100;
System.out.println(refInt.doubleValue());
}
컴파일도 이상 없이 되며, 실행도 잘 된다. 그렇다면, 왜 혼동되게 이러한 숫자를 처리하는 참조 자료형을 만들었을까? 그 이유는 다음과 같다.
라고 생각할 수 있다.
기본 자료형을 참조 자료형으로 만든 클래스들은 Boolean 클래스들을 제외하고 모두 MIN_VALUE나 MAX_VALUE라는 상수를 갖고 있다. 해당 타입이 나타낼 수 있는 값의 범위를 확인하려면 static으로 선언되어 있는 이 상수들을 다음과 같이 사용하면 된다.
public void numberMinMaxCheck(){
System.out.println("Byte min="+Byte.MIN_VALUE+" max="+Byte.MAX_VALUE);
System.out.println("Short min="+Short.MIN_VALUE+" max="+Short.MAX_VALUE);
System.out.println("Integer min="+Integer.MIN_VALUE+" max="+Integer.MAX_VALUE);
System.out.println("Long min="+Long.MIN_VALUE+" max="+Long.MAX_VALUE);
System.out.println("Float min="+Float.MIN_VALUE+" max="+Float.MAX_VALUE);
System.out.println("Double min="+Double.MIN_VALUE+" max="+Float.MAX_VALUE);
System.out.println("Character min="+(int)Character.MIN_VALUE+" max="+(int)Character.MAX_VALUE);
}
마지막에 Character의 경우에는 그냥 출력할 경우 char 타입으로 출력되므로 알아보기 힘들다. 따라서 int 타입으로 변환하여 그 값을 확인하도록 해 놓았다.
실행 결과
Integer과 Long 타입을 읽기가 어렵다. 이 값을 2진수나 16진수로 표현해서 보면 조금 더 보기 편하다. 예를 들어 Integer의 최소값과 최대값을 2진수와 16진수로 나타낸 결과를 보려면, 다음과 같이 Integer 클래스에서 제공하는 toBinaryString()
라는 메소드를 사용하면 된다.
public void intergerMinMaxCheckBinary(){
System.out.println("Integer BINARY min="+Integer.toBinaryString(Integer.MIN_VALUE));
System.out.println("Integer BINARY max="+Integer.toBinaryString(Integer.MAX_VALUE));
System.out.println("Integer HEX min="+Integer.toHexString(Integer.MIN_VALUE));
System.out.println("Integer HEX max="+Integer.toHexString(Integer.MAX_VALUE));
}
실행 결과
어떤 값을 원하는 진수의 숫자로 표현하고 싶을 때는 직접 구현하는 것보다는 이와 같이 숫자 클래스에서 제공되는 메소드를 사용하면 된다.
그러나 돈 계산과 같이 중요한 연산을 수행할 때, 정수형은 BigInteger, 소수형은 BigDecimal을 사용하여야 정확한 계산이 가능하다. 이 두 클래스는 모두 java.lang.Number 클래스의 상속을 받았으며, java.math 패키지에 선언되어 있다.
참고