Integer 라는 래퍼클래스(Wrapper Class)가 가지고 있는 메서드들이다.
이 메서드 두 개는 String을 int로 바꿀수 있다.
하지만 차이점이라면 반환값에 있다.
Integer.valueOf("10") 은 Integer 타입으로 반환하고,
Integer.parseInt("10") 은 int 타입으로 반환한다.
Integer 타입은 기본형 타입(Primitive Type)인 int형의 박싱(boxing)한 결과이다.
int형을 객체로 쓰기위한 객체이며, 래퍼 클래스로 감싸고 있는 기본형 타입의 값이라고 볼 수 있다.
그럼 하나씩 자세하게 살펴보자.
🤔 Integer.parseInt() 란 무엇인가?
통합개발환경(IDE)인 이클립스(Eclipse)에서 마우스에 갖다대면 위처럼 나온다.
Returns an Integer object holding thevalue of the specified String. The argument isinterpreted as representing a signed decimal integer, exactlyas if the argument were given to the parseInt(java.lang.String) method. The result is an Integer object that represents the integer valuespecified by the string.
문자열 인수를 부호가 있는 십진법인 정수로 구문 분석한다.
첫 번째 문자는 음수 값을 나타내는 ASCII 마이너스 기호 '-' ('\u005Cu002D') 또는 양수 값을 나타내는 ASCII 플러스 기호 '+' ('\u005Cu002B') 일 수 있다는 점을 제외하고 문자열의 문자는 모두 십진수여야 한다.
인수와 기수 10이 parseInt(java.lang.String, int) 메소드에 대한 인수로 주어진 것처럼 결과 정수 값이 반환된다.
매개변수(Parameters) : 구문 분석할 int 표현을 포함하는 문자열
반환값(Return) : 인수로 표현되는 정수 값(십진수)
발생(Throws) : NumberFormatException - 문자열에 구문분석할 정수가 없는 경우
즉, 정수 표현을 할 수 있는 문자열을 매개변수로 넣으면 정수 값이 반환된다.
그런데 정수 표현을 할 수 없는 문자열을 넣는다면 NumberFormatException을 발생시킨다.
🤔 Integer.valueOf()란 무엇인가?
Returns an Integer object holding the value of the specified String. The argument is interpreted as representing a signed decimal integer, exactly as if the argument were given to the parseInt(java.lang.String) method. The result is an Integer object that represents the integer value specified by the string.
In other words, this method returns an Integer object equal to the value of: new Integer(Integer.parseInt(s))
지정한 문자열의 값을 보유하는 정수 객체를 반환한다.
인수는 parseInt(java.lang.String) 메서드에 주어진 인수처럼 부호있는 소수 정수를 나타내는 것으로 해석된다.
결과는 문자열로 지정된 정수 값을 나타내는 정수 객체이다.
즉, 이 메서드는 new Integer(Integer.parseInt(s))와 동일한 정수 객체를 반환하다.
매개변수(Parameters) : 구문 분석할 문자열이다.
반환값(Returns) : 문자열 인수가 나타나는 값을 보유하는 정수 객체
발생(Throws) : NumberFormatException - 문자열을 정수로 구문 분석할 수 없는 경우
즉, 정수 표현을 할 수 있는 문자열을 매개변수로 넣으면 정수 객체가 반환된다.
그런데 정수 표현을 할 수 없는 문자열을 넣는다면 NumberFormatException을 발생시킨다.
🤔 그렇다면 valueOf()와 parseInt()의 반환값들은 서로 같지않은가?
등호 연산자는 기본형 타입의 경우 변수에 저장되어 있는 값을 비교하고, 참조형 타입의 경우 객체의 주소값을 비교한다.
여기서 우리는 valueOf("127")의 반환값은 new Integer(Integer.parseInt("127") 이라는 것을 알고 있다.
🤔 그렇다면 새로운 객체를 만들었기 때문에 a의 값은 false가 나와야 하는것이 아닌가??
하지만 계속하여 새로운 Integer 객체를 생성하는 것은 성능적으로 나쁘다.
그래서 java.lang.Integer에는 -128 ~ 127 사이의 값에 대한 인스턴스를 저장하는 IntegerCache가 있다.
우리가 이 범위의 값을 쓴다면 IntegerCache로부터 Integer 객체를 가져오고, 범위를 넘어가면 새로운 Integer 객체를 반환하게 된다.
그래서 a의 값이 true인 것이다.
이 정수 범위는 일상적인 프로그래밍에서 많이 사용되어 간접적으로 메모리를 절약하게 된다.
캐시 크기는 VM 매개변수에 -XX:AutoBoxCacheMax=<size> 옵션으로 조정할 수 있다.
이러한 캐싱은 Integer 뿐만 아니라 Byte, Short, Long, Character에도 존재한다.
하지만 범위를 수정하는 것은 Integer만 가능하다.
Byte, Short, Long 타입은 -128 ~ 127 사이의 고정된 캐싱 범위를 가지고 있고,
Character는 0 ~ 127 고정된 캐싱 범위를 가지고 있다.
만약 객체에서 값을 비교하고 싶다면 == 이 아닌 equals 를 써야한다.
이제 우리는 valueOf("128") 끼리 비교했을때 Integer 객체가 새로 생성되었기에 주소값이 달라 false가 나온다는 것을 알 수 있다.
parseInt 끼리의 비교는 당연히 값을 비교하기에 true가 나온다는 것을 알 수 있다.
🤔 parseInt와 valueOf 비교값은 왜 true인가?
JDK1.5버전부터는 참조형의 경우 컴파일러가 Integer객체를 int 타입으로 값을 변환해주는 intValue()를 추가하여 오토언박싱을 하거나 오토박싱을 한다. 그래서 기본형과 참조형 간의 연산이 가능하다.
그렇다면 왜 래퍼클래스(wrapper class)가 기본형(primitive type)으로 Unboxing(언박싱)하는지 알아보자.
Java SE8 API 공식문서 15.21.1. Numerical Equality Operators == and !=
If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).
항등 연산자의 피연산자가 모두 숫자 유형이거나 하나가 숫자 유형이고 다른 하나가 숫자 유형으로 변환 가능한 경우 피연산자(5.6.2)에 대해 이진 숫자 승격이 수행됩니다.
Java SE8 API 공식문서 5.6.2. Binary Numeric Promotion
When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order:
1. If any operand is of a reference type, it is subjected to unboxing conversion (§5.1.8).
2. Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
- If either operand is of type double, the other is converted to double.
- Otherwise, if either operand is of type float, the other is converted to float.
- Otherwise, if either operand is of type long, the other is converted to long.
- Otherwise, both operands are converted to type int.
연산자가 각각 숫자 유형으로 변환할 수 있는 값을 나타내야하는 피연산자 쌍에 이진 숫자 승격을 적용할 때 다음 규칙이 순서대로 적용됩니다.
1. 피연산자가 참조유형인 경우 Unboxing 변환 대상이다.
2. 확장 기본 변환(5.1.2)은 다음 규칙에 지정된 대로 피연산자 중 하나 또는 둘 모두를 변환하는데 적용된다.
- 피연산자 중 하나가 double 타입이면, 다른 하나는 double로 변환된다.
- 그렇지 않고, 피연산자 중 하나가 float 타입이면, 다른 하나는 float로 변환된다.
- 그렇지 않고, 피연산자 중 하나가 long 타입이면, 다른 하나는 long으로 변환된다.
- 그렇지 않으면 두 피연산자 모두 int 타입으로 변환된다.
위 Binary Numeric Promotion을 요약하면 피연산자 하나가 참조 유형이면 언박싱(Unboxing) 대상이고,
기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환을 해야하므로
double -> float -> long -> int 타입순으로 값의 범위가 큰것에서 작은것으로 체크하는 것이다.
이와 같은 규칙들이 있으므로 parseInt는 기본형, valueOf는 참조형이므로 참조형을 언박싱하여 값을 비교하게 되는 것이고, true가 나오는 것이다.
'프로그래밍 > Java' 카테고리의 다른 글
JVM(자바가상머신)이란? - Part 2, Execution Engine (0) | 2022.01.26 |
---|---|
JVM(자바가상머신)이란? - Part 1, 소개 (0) | 2022.01.23 |
컬렉션 프레임워크(Collections Framework) (0) | 2022.01.19 |
Java 언박싱 형변환 (0) | 2022.01.14 |
함수형 인터페이스(Functional Interface)란 무엇인가? (0) | 2022.01.13 |