참고
기본형의 한계
기본형은 객체가 아니다
NOTE
자바에서 기본형 데이터는 효율성과 성능을 위해 객체로 표현되지 않아 객체지향 프로그래밍의 특징을 활용하지 못하는 한계를 가집니다.
public static void main(String[] args) {
int value = 10;
int i1 = compareTo(value, 5);
int i2 = compareTo(value, 11);
int i3 = compareTo(value, 10);
System.out.println("i1 = " + i1);
System.out.println("i2 = " + i2);
System.out.println("i3 = " + i3);
}
// 비교함수
public static int compareTo(int value, int targer) {
if (value < targer) {
return -1;
} else if (value > targer) {
return 1;
}else{
return 0;
}
}
Java
복사
•
value는 비교 대상 값을 compareTo()라는 외부 메서드를 통해서 비교합니다.
•
만약 value가 객체라면 value 객체 스스로 자기 자신의 값과 다른 값을 비교하는 메서드를 만드는 것이 더 유용할 것입니다.
public class MyInteger {
private final int value;
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); //숫자를 문자로 변경
}
}
Java
복사
public static void main(String[] args) {
MyInteger myInteger = new MyInteger(10);
int i1 = myInteger.compareTo(5);
int i2 = myInteger.compareTo(11);
int i3 = myInteger.compareTo(10);
System.out.println("i1 = " + i1);
System.out.println("i2 = " + i2);
System.out.println("i3 = " + i3);
}
Java
복사
객체의 메서드사용
기본형과 Null
NOTE
자바 기본타입은 Null 값을 가질 수 없이 항상 초기화되어야 합니다. 이는 아직 값이 초기화되지 않은 상태를 표현하는데 제약을 만들 수 있습니다.
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));
System.out.println(findValue(intArr, 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; // 데이터가 없다는 의미인 -1
}
Java
복사
데이터가 없다면 -1 반환
•
-1이 약속된 값이라고 하더라도, 처음 보는사람은 -1이 있어서 반환한것인지 아니면 값이 없어서 -1을 반환한것인지 명확하지가 않습니다.
•
객체의 경우에는 null이라는 명확한 값이 존재합니다.
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)); // null
}
private static MyInteger findValue(MyInteger[] intArr, int target) {
for (MyInteger myInteger : intArr) {
if (myInteger.getValue() == target) {
return myInteger;
}
}
return null;
}
Java
복사
데이터가 없다면 Null 반환
래퍼 클래스
NOTE
자바는 위에서 다룬 기본형의 한계를 극복하기 위해서 기본형에 대한 객체를 제공하며 이를 래퍼 클래스라고 합니다.
public static void main(String[] args) {
// 래퍼 클래스 생성(박싱)
Integer newInteger = new Integer(10); //미래에 삭제 예정, 대신에 valueOf() 사용
Integer integerObj = Integer.valueOf(10); //-128 ~ 127 자주 사용하는 숫자 값재사용, 불변
Integer autoBoxing = 10; // 오토박싱
Long longObj = Long.valueOf(100);
Double doubleObj = Double.valueOf(10.5);
System.out.println("newInteger = " + newInteger);
System.out.println("integerObj = " + integerObj);
System.out.println("longObj = " + longObj);
System.out.println("doubleObj = " + doubleObj);
System.out.println("내부 값 읽기");
// 래퍼 클래스 -> 기본형(언박싱)
int intValue = integerObj.intValue();
Integer intValue2 = intValue; // 오토 언박싱
System.out.println("intValue = " + intValue);
long longValue = longObj.longValue();
System.out.println("longObj = " + longValue);
System.out.println("비교");
System.out.println("==: " + (newInteger == integerObj));
System.out.println("equals: " + newInteger.equals(integerObj));
}
Java
복사
래퍼 클래스 예제코드
•
new Integer(10)과 같이 생성자를 통해 만들지말고 valueOf()를 통해 생성하는것을 권장합니다.
◦
valueOf()에서도 new Integer()를 동일하게 사용하지만, 성능 최적화 기능이 존재합니다.
•
자바 1.5부터는 박싱-언박싱이 자동으로 이루어지도록 컴파일러가 개발자 대신 valueOf(), xxxValue()등의 코드를 추가해줄 수 있도록 지원해줍니다.
주요 메서드와 성능
NOTE
래퍼 클래스는 기본형 데이터를 객체로 사용할 수 있도록 돕고, 다양한 유틸리티 메서드를 제공하여 객체지향 코딩을 지원합니다. 그러나 박싱-언박싱 과정에서 오버헤드가 발생할 수 있습니다.
public static void main(String[] args) {
Integer i1 = Integer.valueOf(10); // 숫자를 래퍼 객체로 반환
Integer i2 = Integer.valueOf("10"); // 문자열을 래퍼 객체로 반환
int intValue = Integer.parseInt("10"); // 문자열 전용, 기본형 반환
// 비교 - compareTo
int compareResult = i1.compareTo(20);
System.out.println("compareResult = " + compareResult);
// 산술 연산 - sum, min, max
System.out.println("sum: " + Integer.sum(10, 20));
System.out.println("min: " + Integer.min(10, 20));
System.out.println("max: " + Integer.max(10, 20));
}
Java
복사
•
parseInt()는 기본형을 반환하고, valueOf()는 래퍼 타입을 반환합니다. 따라서 원하는 타입에 맞는 메서드를 선택하여 사용하면 됩니다.
public static void main(String[] args) {
int iterations = 1_000_000_000;
long startTime, endTime;
// 기본 타입 경우
long sumPrimitive = 0;
startTime = System.currentTimeMillis();
for (long i = 0; i < iterations; i++) {
sumPrimitive += i;
}
endTime = System.currentTimeMillis();
System.out.println("sumPrimitive = " + sumPrimitive);
System.out.println("기본 자료형 long 실행 시간 " + (endTime - startTime) + "ms");
// 래퍼 클래스 경우
Long sumWrapper = Long.valueOf(0);
startTime = System.currentTimeMillis();
for (long i = 0; i < iterations; i++) {
sumWrapper += i; // 오토박싱이 수없이 발생함!
}
endTime = System.currentTimeMillis();
System.out.println("sumWrapper = " + sumWrapper);
System.out.println("래퍼 클래스 Long 실행 시간 " + (endTime - startTime) + "ms");
}
Java
복사
기본타입과 래퍼클래스의 성능
•
위의 코드에서 래퍼 클래스를 이용해 기본형 long을 더하는 경우, 오토박싱으로 발생하는 오버헤드 때문에 일반적으로 기본 타입이 약 1초 더 빠르게 처리됩니다.
◦
저의 경우, 10억 번의 연산에서 래퍼 클래스가 더 빠르게 처리되었습니다. 자바 버전과 컴퓨터 성능에 따라, 이제는 거의 의미 없는 성능 최적화 단계에 도달한 것 같습니다.
이상하게 기본형이 느리게 나온다..
•
그러나 10억 번의 연산에서 1초의 차이는 실질적으로 큰 의미를 가지지 않습니다. 최적화가 중요한 경우에는 고려해야 하지만, 일반적으로 유지보수 측면에서 래퍼 클래스가 더 유용하다면 래퍼 클래스를 사용하는 것이 바람직합니다.
•
대부분의 웹 애플리케이션에서 최적화는 메모리에서의 연산을 줄이는 것보다 네트워크 호출을 줄이는 것이 더 효과적인 경우가 많습니다.