목표
Java에서 문자열(String)을 생성하는 방법과 문자열을 비교할 때 Equals() 메소드와 == 연산자의 차이점에 대해서 알아보겠습니다.
목차 클릭하면 해당 목차로 이동합니다.
개요
Spring 프레임워크를 배우기 위해 Java를 공부하고 있습니다. 부스트코스에서 egoing님의 강의를 듣고 있는데, 문자열을 비교할 때 == 대신 equals()를 사용해야 한다고 합니다. 안그래도 Java에서 String 객체를 기본적으로 지원해주는 것에 흥미를 느끼고 있었는데, 이때다 싶어서 문자열에 관한 내용에 대해서 자세히 찾아봤습니다. 기본적으로 문자열(String)은 Java의 최상위 클래스인 Object에 속해있는 String 클래스의 객체입니다. 이와 관련된 메소드를 Java 문서와 구글링을 통해 알아보았습니다.
문자열 생성
문자열을 비교하기에 앞서, 먼저 문자열을 생성하는 방법을 확인해보겠습니다. 문자열을 생성하는 방법은 다음과 같이 2가지가 있습니다.
String str1 = "One"; //String literal을 사용하는 방법
String str2 = "One";
String str3 = new String("Two"); // new 연산자를 사용하는 방법
String str4 = new String("Two");
String str5 = new String("One");
str1, str2처럼 String literal로 생성하는 방법과 str3, str4, str5처럼 new 연산자를 사용해 생성하는 방법이 있습니다. 결과적으로 큰따옴표 안에 있는 문자열이 생성되는 것은 같지만, 내부적으로 저장되는 위치가 다릅니다. new 연산자를 활용한 경우 사용자가 생성한 String 객체이므로, Heap 내부에 저장됩니다. 리터럴을 사용해 생성된 문자열은 Heap 내부에 존재하는 Constant String Pool에 저장됩니다.
str1과 str5는 "One"으로 값이 같지만, 다른 위치에 있는 문자열 객체의 값을 저장하는 것입니다. 그림으로 확인하면 다음과 같습니다.
위 그림처럼, String Pool에 저장된 문자열 객체는 똑같은 값을 또 생성해도 같은 위치에 있는 객체를 저장하게 됩니다. 반면, new 연산자를 사용해 새로운 객체를 생성할 경우, heap 내부에 새로운 객체를 만들어 저장하게 됩니다.
문자열 비교
이렇게 생성된 문자열을 비교해보도록 하겠습니다. 흔히 비교를 할 때는 '==' 연산자를 사용하게 됩니다. 위에서 생성한 문자열을 각각 비교해보는 예제를 확인해보도록 하겠습니다.
String str1 = "One";
String str2 = "One";
String str3 = new String("Two");
String str4 = new String("Two");
String str5 = new String("One");
if (str1 == str2) {
System.out.println("str1 == str2");
} else {
System.out.println("str1 != str2");
}
if (str1 == str5) {
System.out.println("str1 == str5");
} else {
System.out.println("str1 != str5");
}
[결과]
str1 == str2
str1 != str5
str1과 str5는 "One"으로 값이 같은데 왜 조건문이 False를 반환하는 걸까요? 그 이유는, '==' 연산자에 있습니다. '==' 연산자는 해당 문자열의 주소를 비교합니다. str1, str2는 같은 주소에 있는 문자열의 값을 갖고 있기 때문에 비교했을 때 True를 반환하지만, str1, str5는 같은 문자열임에도 불구하고 다른 위치에 있는 문자열의 값을 갖고 있으므로, False를 반환하는 것입니다. 보통 이러한 상황에서 우리가 원하는 것은 주소를 비교하는 것이 아닙니다.
우리가 원하는 것은 값이 같은지를 묻는 것이고, 이 때 equals() 메소드를 사용하게 됩니다. equals() 메소드는 문자 하나하나를 비교하여 "값"이 같으면 True를 반환하는 것입니다. 다음 예제를 확인해보도록 하겠습니다.
String str1 = "One";
String str2 = "One";
String str3 = new String("Two");
String str4 = new String("Two");
String str5 = new String("One");
if (str1.equals(str2)) {
System.out.println("str1 == str2");
} else {
System.out.println("str1 != str2");
}
if (str1.equals(str5)) {
System.out.println("str1 == str5");
} else {
System.out.println("str1 != str5");
}
[결과]
str1 == str2
str1 == str5
주소를 비교하는 '==' 연산자와 달리, 문자 하나하나 비교해서 값이 같은지 확인하는 equals() 메소드는 str1과 str5를 같다고 판단하는 것을 확인할 수 있습니다.
eqauls() 메소드의 존재 이유?
Java는 데이터 타입을 원시(primitive) 데이터 타입인지, 아닌지에 따라 크게 두 가지로 나눌 수 있습니다.
원시 데이터 타입은 기본적으로 java에서 지원하는 데이터 타입 8개를 의미합니다.
- 원시 데이터 타입: short, byte, int, long, char, float, double, boolean
- 그 외 데이터 타입: String, Date, 사용자 작성 클래스 등등
이를 구분하는 이유는 데이터가 메모리에 저장되는 방법이 다르기 때문입니다. 원시 데이터 타입은 데이터를 저장하게 되면 메모리에 값을 저장합니다. 동일한 값을 저장하면 같은 주소에 있는 값을 저장합니다. 이는, 위에서 리터럴 방식으로 문자열을 생성하는 것과 동일합니다. 반대로, 원시 데이터 타입이 아닌 경우, 같은 데이터라도 새로운 메모리 공간에 생성하여 저장하게 됩니다. 위에서 다뤘듯, '==' 연산자는 데이터의 주소를 비교하는 연산자입니다. 원시 데이터 타입이 아니라면, 다른 주소에 저장되어 있기 때문에, 대부분의 비원시적(non-primitive) 데이터 타입은 equals() 메소드를 지원하는 것입니다.
intern() 메소드
new 연산자를 사용해 문자열을 생성할 때, String Pool에 저장할 수 있는 방법이 있습니다. 자바의 String 클래스에 intern() 메소드가 존재하는데, 이는 문자열 객체가 이미 String Pool에 존재하면 해당 객체를 반환하도록 하는 메소드입니다. 만약, String Pool에 존재하지 않는다면 String Pool에 문자열 객체를 생성하고 해당 주소를 반환합니다. 이와 관련한 예제를 확인해보도록 하겠습니다.
String str1 = "abc";
String str2 = new String("abc").intern();
if (str1 == str2)
System.out.println("Same");
else
System.out.println("Different");
[결과]
Same
str2는 new 연산자를 활용해 문자열을 생성했지만, str1과 같은 주소값을 갖고 있는 것을 확인할 수 있습니다.
정리
1. 문자열 생성하는 방법은 2가지가 있다.
- 리터럴을 이용하는 방법 (예:String a = "문자열") → String Pool에 저장
- new 연산자를 이용하는 방법 (예:String a = new String("문자열")) → Heap 내부에 저장
2. 문자열을 비교하는 연산자 '=='과 equals의 차이점은 다음과 같다.
- '==' 연산자는 문자열의 주소를 비교한다.
- equals() 메소드는 문자열의 값을 비교한다.
3. intern() 메소드를 활용해 new 연산자를 이용해 문자열을 생성해도 String Pool에 저장할 수 있다.
이렇게 문자열에 대한 내용을 알아보았습니다. 지나가듯 들었던 문자열을 new 연산자를 통해 생성하면 좋지않다고 말하는 이유에 대해서 알게되었습니다. C언어보다 훨씬 쉽게 문자열을 구현할 수 있는 것이 정말 흥미로운 것 같습니다.
'개발 > JAVA' 카테고리의 다른 글
[JAVA] 정규표현식으로 문제 해결하기 (0) | 2022.12.10 |
---|---|
[JAVA] 객체지향프로그래밍(OOP)의 클래스와 객체 그리고 인스턴스 (2) | 2022.03.16 |