어떤 프로그래밍 책을 보더라도 거의 처음부터 나오는 개념이면서도 기초 중에 기초라고 생각했던 String에 대해 얼마나 알고 있었던 걸까요? 오늘은 평소에 굉장히 자주 접하는 String에 대해서 정리를 해보려고 합니다.
아래 자바 코드는 몇 개의 객체를 생성할까요? 그리고 다음 코드의 실행 결괏값은 어떤 식으로 출력될까요?
public class ExcampleString{
public static void main(String[] args){
String str1 = "Banana";
String str2 = "Banana";
String str3 = new String("Banana");
String str4 = new String("Banana");
System.out.println("str1 == str2 : " + (str1 == str2) );
System.out.println("str1 == str3 : " + (str1 == str3) );
System.out.println("str1 == str3.intern() : " + (str1 == str3.intern()) );
System.out.println("str3 == str3.intern() : " + (str3 == str3.intern()) );
System.out.println("str2 == str4.intern() : " + (str2 == str4.intern()) );
System.out.println("str1.equals(str3) : " + str1.equals(str3) );
System.out.println("str1.equals(str4) : " + str1.equals(str4) );
}
}
결과부터 보자면 콘솔 출력 값은 아래와 같습니다.
str1 == str2 : true
str1 == str3 : false
str1 == str3.intern() : true
str3 == str3.intern() : false
str2 == str4.intern() : true
str1.equals(str3) : true
str1.equals(str4) : true
자바에서 String은 가장 대표적인 "참조 자료형"입니다. 그리고 굉장히 특별하게도 String객체의 생성 방식은 2가지가 존재합니다.
1) String str = " hoon "; 과 같이 큰따옴표 안에 값을 입력해서 넣는 방식.
2) new연산자를 이용한 방식
두 방식 모두 자바의 String을 생성하는 것은 틀림없습니다. 그런데 어떤 점이 다른걸까요?
(출처: https://www.journaldev.com/797/what-is-java-string-pool)
그것은 바로 생성되는 메모리 영역인데요. new를 통해 생성한 String은 다른 참조 자료형과 동일하게 Heap영역에 메모리가 생성되고, 큰 따옴표(" ")로 생성한 String은 heap영역 내부에 존재하는 string constant pool영역에 생성되는 특징을 가지고 있습니다.
먼저 String은 immutable(※사전적 의미: 불변의)한 속성을 가지고 있습니다. 말 그대로 값이 변하지 않는다는 말인데요. 다시 말해, String에 한번 저장된 값은 변하지 않는 특징을 가지고 있습니다. 예를 들어, 위 그림의 변수 s2를 가지고 s2 = s2 + s2; 한다고 해봅시다. 그러면 자바 내부적으로는 기존의 값 Cat을 삭제하지 않고 그대로 두면서, 새로운 메모리를 할당해 "CatCat"을 생성한다는 말입니다. 그래서 메모리 관리 측면에서 사용 방식에 따라 비효율적일 수도 있는 문제가 있습니다. 그래서 만들어진 영역이 string constant pool인데요, 이 영역에 생성된 '값이 같은 String'은 같은 레퍼런스(주소)를 가지게 됩니다.
왜 그럴까요??
큰따옴표(" ")로 생성한 String은 내부적으로 intern()메소드를 호출하기 때문입니다. intern()메소드는 주어진 문자열이 string constant pool에 있는지 검색하여 있다면 해당 주소를 반환하고, 없다면 string constant pool에 넣고 새로운 주소 값을 반환하는 동작을 합니다. 쉽게 말해, intern()메소드는 heap메모리에 있는 String객체를 string constant pool에 집어넣는 역할을 합니다. 그래서 str1 == str3은 false이고 , str1 == str3.intern()은 true가 되는 것입니다.
str1 == str3 :false
str1 == str3.intern() : true
str1.equals(str3) : true
str1.equals(str4) : true
==연산자와 equals()메소드 비교
1) ==연산: 기본 형식은 갖고 있는 값의 일치 여부를 반환. 클래스 형식은 같은 객체를 참조하는지 여부를 반환.
2) equals메소드: 서로 다른 객체여도 String객체의 값인 문자열이 같은 값인지 여부를 확인.
결론! 다시 처음 문제로 돌아와서 풀어보면
String str1 = "Banana";
String str2 = "Banana";
String str3 = new String("Banana");
String str4 = new String("Banana");
생성된 객체의 수는!!!?? 정답은 3개가 되는 것입니다.
'Java' 카테고리의 다른 글
Method invocation may produce NullPointerException 과 Optional 활용 (0) | 2024.10.11 |
---|---|
[OOP] 왜 Class가 아니라 Object Oriented Programming 일까? (0) | 2024.08.26 |
경로(Path) 설정시 *, ** 차이 (0) | 2023.04.13 |
break와 return, continue 차이 및 특징 정리 (0) | 2019.02.15 |