자바에서 문자열은 String 클래스의 객체를 만드는 방식으로 구현된다. 즉, 문자열은 다른 데이터들과는 다르게 참조형 데이터 타입(그 중에서도 object 데이터 타입)을 가진다.
그런데 이런 String 클래스는 그 자체만으로 문자열을 조작하는 데에 불편함이 많다.
예를 들어
String str = new String("abc");
String str2 = new String("abc");
라는 코드를 통해 문자열 객체를 생성했다면,
이 둘은 똑같은 내용을 가짐에도 불구하고 서로 다른 문자열 객체이다. 즉 str과 str2는 서로 다른 객체를 참조한다.
물론
String str = "ABC";
String str2 = "ABC";
일반적으로 문자열 객체를 생성하는 위와 같은 방식을 사용했을 때에는 메모리에 같은 내용을 가지는 객체가 있는지 확인하고, str과 str2가 같은 객체를 참조한다.
문자열을 정의할 때마다 새로운 객체를 만들어낸다는 String 클래스의 단점은 위와 같은 방식으로 해결될 수 있다. 그렇지만 String 클래스는 여전히 문자열 조작의 제약점이 있는데, 바로 String의 불변성(immutability)
이다.
예를 들어,
str.concat(str2);
concat이라는 String class의 메서드를 이용해서 str과 str2를 붙인다고 할 때, 이 메서드는 둘을 붙인 결과를 리턴하지만, str이나 str2가 참조하는 객체 자체는 바뀌지 않는다.
따라서 이를 바꾸기 위해서는 변경된 결과값을 다시 변수에 대입해주는 과정이 필요하다. 이는 replaceAll, split, trim과 같은 메서드에 대해서도 똑같이 적용된다.
이런 단점을 해결하기 위해서 사용하는 것이 바로 StringBuffer
와 StringBuilder
클래스이다.
StringBuffer sb = new StringBuffer("abc");
sb.append("123");
StringBuffer 클래스의 append 메서드를 사용하면 sb가 참조하는 객체 자체가 변경된다.
cf)
StringBuffer 클래스는 String 클래스와 달리
equals 메서드를 오버라이딩하지 않았기 때문에,
Object 클래스에서와 같이 주소값을 비교한다.
기본형 데이터 타입과 참조형 데이터 타입 간의 형 변환을 할 수 있도록 해주는 매개체가 래퍼 클래스이다. 객체 지향에서는 모든 것이 객체로 다뤄져야하는데, 자바의 기본형 데이터들은 편의성을 위해 이러한 객체 지향의 개념 밖에 존재한다. 그러나 때로는 이것들을 객체로 다뤄야할 경우가 있는데, 이를 위해 존재하는 것이 래퍼 클래스이다.
// 정수 객체 생성
Integer obj = new Integer(8);
래퍼 클래스 종류
Boolean, Character, Byte, Short, Integer, Long, Float, Double
예를 들어 정수형 자료를 담는 기본형 데이터 타입은 int, 참조형 데이터 타입은 Integer이다. (문자열 변환을 위해 사용하는 Integer.parseInt()
도 바로 이 Integer 클래스의 정적 메소드이다.)
int i = 10;
Integer obj = Integer.valueOf(i);
원래는 이런 과정을 거쳐서 기본형 데이터를 참조형 데이터로 변환하고,
num1 = obj1.intValue();
참조형 데이터를 기본형 데이터로 변환한다. (JDK 1.5 이전)
그러나 JDK 1.5 이후로는 보다 편한 형변환을 위해 auto boxing
(기본형 데이터를 래퍼 클래스의 인스턴스에 담는 것)과 unboxing
을 지원한다.
따라서 다음과 같은 형변환이 가능하다.
int i = 10;
Integer obj = (Integer) i; // i 오토 박싱(기본형 -> 참조형)
int sum = i + obj; // obj 언박싱(참조형 -> 기본형)
cf)
숫자와 관련된 래퍼 클래스들은 모두 Number 클래스의 자손이다.