우선, 글을 작성하기 전 이 글의 모든 내용은 김영한님의 JAVA 강의를 바탕으로 함을 알립니다.
객체 지향 언어인 Java가 제공하는 기본형(Primitive Type)은 객체가 아니기에 두 가지의 한계점이 존재한다.
public class MyIntegerMethodMain0 {
public static void main(String[] args) {
int value = 10;
int i1 = compareTo(value,5);
int i2 = compareTo(value,10);
int i3 = compareTo(value,20);
System.out.println("i1 = " + i1);
System.out.println("i2 = " + i2);
System.out.println("i3 = " + i3);
}
public static int compareTo(int value, int target) {
if (value < target) {
return -1;
} else if (value > target) {
return 1;
} else {
return 0;
}
}
}
위의 예제를 보면 compareTo메서드를 통해 value와 다른 정수를 비교하여 비교에 따른 반환값을 반환하여 출력한다. 비교 대상을 보면 value와 다른 정수들이고 value는 계속해서 사용되는 것을 알 수 있다. 만약 value가 기본형이 아닌 참조형이었다면 value객체가 자기 자신과 다른 정수를 비교하는 compareTo메서드를 만드는 것이 객체 지향적이었을 것이다.
public class MyInteger {
private final int value; // int 타입의 기본형 변수를 하나 갖고 있고 클래스화 했기에 유용한 메서드를 만들어서 사용 가능
public MyInteger(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public int compareTo(int target) {
if (value < target) {
return -1;
} else if (value > target) {
return 1;
} else {
return 0;
}
}
@Override
public String toString() {
return String.valueOf(value);
}
}
위의 MyInteger클래스처럼 기본형을 참조형으로 만들었을 경우 메서드를 통해 자기 자신의 값(value)와 다른 정수를 비교할 수 있다. 즉, 객체 입장에서 문제를 해결할 수 있다.
없음의 개념을 표현 할 수 없다. 기본형은 항상 값을 가지기 때문에 없음을 표현할 수 없다.public class MyIntegerNullMain0 {
public static void main(String[] args) {
int[] intArr = {-1, 0, 1, 2, 3};
System.out.println(findValue(intArr,-1)); //-1
System.out.println(findValue(intArr,0)); //0
System.out.println(findValue(intArr,1)); //1
System.out.println(findValue(intArr,100)); //-1
}
private static int findValue(int[] intArr, int target) {
for (int value : intArr) {
if (value == target) {
return value;
}
}
return -1; // int는 기본형으로 무조건 값이 있어야한다.
}
}
위의 예제는 findValue메서드를 통해 intArr에 존재하는 정수와 target정수를 비교해서 동일하면 정수를 반환하고 다르면 -1을 반환하는 예제이다. 근데 여기서 문제점이 발생한다.
System.out.println(findValue(intArr,-1)); //-1
이 부분을 보면 target이 -1이고 intArr배열은 -1을 원소로 갖고 있다. findValue메서드에 의해 결과가 -1이 반환되었다면 value가 -1이어서 target과 동일하여 반환된 것인지, value가 -1이 아니어서 target과 다르기에 반환된 것인지 어떻게 알까? 기본형이기에 불가능한 것이다. 참조형을 살펴보자.
public class MyIntegerNullMain {
public static void main(String[] args) {
MyInteger[] intArr = {new MyInteger(-1), new MyInteger(0), new MyInteger(1)};
System.out.println(findValue(intArr, -1));
System.out.println(findValue(intArr, 0));
System.out.println(findValue(intArr, 1));
System.out.println(findValue(intArr, 100));
}
private static MyInteger findValue(MyInteger[] intArr, int target) { // 래퍼 클래스 사용
for (MyInteger myInteger : intArr) {
if (myInteger.getValue() == target) {
return myInteger;
}
}
return null; // 래퍼클래스를 통해 참조형으로 바뀌어 null 사용 가능
}
}
참조형의 경우 Null을 사용할 수 있기에 조건에 부합하지 않는경우 Null을 통해 표현이 가능하다.
기본형은 객체가 아니기에 '자기 자신'입장에서 특정 기능을 제공 할 수 없다는 것과 값이 '없음'을 표현할 수 없다는 단점을 갖는다. Java는 기본형의 단점을 보완할 수 있는 래퍼 클래스를 제공한다.
Wrap을 직역하면 "포장하다","감싸다"로 해석할 수 있다.
래퍼 클래스는 기본형을 객체로 감싸서 객체의 기능을 갖도록 하는 클래스이다. 즉, 기본형의 객체화라고 보면된다.
byte → Byteshort → Shortint → Integerlong → Longfloat → Floatdouble → Doublechar → Characterboolean → Booleanequals를 통해 동등성 비교를 해야한다박싱(boxing) : 물건을 박스에 넣는 행위, 기본형을 래퍼 클래스로 변경하는 것언박싱(Unboxing) : 박스의 물건을 꺼내는 행위, 래퍼 클래스를 다시 기본형으로 꺼내는 것public class WrapperClassMain {
public static void main(String[] args) {
// 박싱(Boxing)
Integer newInteger = new Integer(10); // 삭제 예정 -> valueOf() 사용 권장
Integer integerObj = Integer.valueOf(10);
Long longObj = Long.valueOf(100);
Double doubleObj = Double.valueOf(10.5);
System.out.println("newInteger = " + newInteger); // newInteger = 10
System.out.println("integerObj = " + integerObj); // integerObj = 10
System.out.println("longObj = " + longObj); // longObj = 100
System.out.println("doubleObj = " + doubleObj); // doubleObj = 10.5
// 언박싱(Unboxing)
System.out.println("내부 값 읽기");
int intValue = integerObj.intValue(); // intValue = 10
long longValue = longObj.longValue(); // longObj = 100
System.out.println("intValue = " + intValue);
System.out.println("longObj = " + longValue);
System.out.println("비교");
System.out.println("==: " + (newInteger == integerObj)); // ==: false
System.out.println("equals: " + newInteger.equals(integerObj)); // equals: true
}
}
valueOf() - 박싱(Boxing)
Integer.valueOf(num)는 단순히 num에 해당하는 정수를 박싱하는 기능뿐만아니라 성능 최적화 기능이 있다. -128~128 범위의 Integer 클래스를 미리 생성하고, 해당 범위의 값이 조회되면 미리 생성된 Integer 객체를 반환한다. 마치 문자열 풀과 비슷하게 미리 생성하고 필요시 제공하는 방식이다. intValue() - 언박싱(Unboxing)
비교는 equals()
개발자들에 의해 박싱과 언박싱의 사용 빈도가 늘며 변환 과정에 있어서 더 나은 편의를 제공하기 위해 오토 박싱과 오토 언박싱을 지원한다.
오토박싱과 오토 언박싱은 valueOf(),intValue()와 같은 메서드를 사용하지 않고 박싱과 언박싱을 진행하는 것이다. 예제를 살펴보자
public class AutoboxingMain2 {
public static void main(String[] args) {
//Primitive -> Wrapper ,, boxing
int value = 7;
// Integer boxedValue = Integer.valueOf(value);
Integer boxedValue = value; // 오토 박싱(Auto boxing)
//Wrapper -> Primitive ,, unboxing
// int unboxedValue = boxedValue.intValue();
int unboxedValue = boxedValue; // 오토 언박싱(Auto unboxing)
System.out.println("boxedValue = " + boxedValue);
System.out.println("unboxedValue = " + unboxedValue;
}
}
예제를 보면 오토 박싱과 오토 언박싱은 생성된 래퍼 클래스 객체에 일반 '값'을 저장하는 형태로 진행된다.
Integer boxedValue = value; // 오토 박싱(Auto boxing)
int unboxedValue = boxedValue; // 오토 언박싱(Auto unboxing)
오토 박싱과 오토 언박싱은 컴파일러가 대신 valueOf,xxxValue()의 코드를 추가해주는 기능이다.
valueOf() : 래퍼 타입 반환, 숫자, 문자열 모두 지원parseInt() : 기본형 타입 반환, 문자열을 기본형으로 변환 compareTo() : 내 값과 인수로 넘어온 값을 비교. 내 값이 크면 1, 같으면 0, 작으면 -1을 반환Integer.sum(),Integer.min(),Integer.max() : static메서드, 간단한 사칙연산 수행