Java/Java

[Java] String 객체 비교 이해하기

hyeon.q 2024. 3. 14. 15:52
728x90

안녕하세요 

오늘은 String 객체에 대한 이야기를 해보겠습니다.

 

문자열 생성

 

문자열은 자바에서 객체로 취급한다는거 알고 계셨나요?

int,double,char는 원시 타입으로 해서 객체가 아닙니다. 

그러므로 자체적으로 구현된 메소드들 또한 없죠. 위 타입을 객체 처럼 사용하기 위해서는

이미 만들어진 Wrapper 클래스를 사용하면 됩니다.

한번 String 객체를 생성해 보겠습니다.

// 1
String str1 = new String("Hello World");
String str2 = new String("Hello World");

// 2
String str3 = "Hello World";
String str4 = "Hello world";

 


위 사진은 보기 코드에 첫번째 new 로 객체를 생성했을 때의 메모리 구조입니다.

String 안에 들어가 있는 값은 같지만, 각각의 객체를 생성했기 때문에

메모리 공간이 총 2개가 만들어집니다.

 

그리고 위 객체를 비교해보면

str1==str2;
str1.equals(str2);

false
true

 

위 결과를 얻게 됩니다. 간단하게 설명을 하자면

== 연산자는 Stack 메모리의 주소를 비교합니다. 그러므로 원시 타입을 비교할때 알맞겠죠?

그러므로 두 객체는 각각의 다른 메모리 공간을 가지고 있음으로 false가 나옵니다

 

그러나 equals 메소드는 Heap 메모리에 저장된 실제 값을 비교합니다

Heap 메모리에 저장된 두 값은 'Hello World' 로 같은 값을 가지니 true가 나옵니다.

 

 


위 사진은 new로 객체를 생성하지 않았을 때 문자열 메모리 입니다.

stack 메모리에 2가지 주소가 생깁니다

그리고 오른쪽에 메모리 공간을 보면 Heap이 아닌 Literal Pool Memory 라는 공간에 저장되어 있습니다

자바에는 String 문자를 저장하는 공간이 따로 마련되어 있습니다

그 공간은 Literal Pool 이라고 부르고요

 

일반적인 String 변수를 선언하면 Heap 메모리에 값이 저장되지 않고,

Literal Pool 에 저장이 됩니다.

        String str1 = "abc";
        String str2 = "abc";


        System.out.println(str1.equals(str2));
        System.out.println(str1==str2);

위 값을 비교를 하면은

true
true

 

가 나옵니다. 왜그럴까요?

String 은 이미 만들어진 변수와 같은 값을 가진 변수가 있으면

객체를 새로 만들지 않고, 같은 주소를 가리키게 만든다

그게 가능한 이유는 Literal Pool 은 재활용이 가능한 성질이 있기 때문입니다

 

그래서 == ,equals()를 비교해도 true 가 나오는 것 입니다.

 

그럼 이번에는 위 new로 생성한 객체와 new가 없이 생성한 객체를 비교하면 같은 문자로 취급할까?

위 고민을 해결하기 위해서 테스트를 해본 결과 false 가 나왔습니다.

왜 그런걸까요?

이제 한번 알아보겠습니다.

public class Ex1 {
    public static void main(String[] args) {
        String str1 = "abc";
        String str2 = new String("abc");

        System.out.println(str1==str2);
        System.out.println(str1.equals(str2));
    }
}

false
true

 

위 코드를 실행시켜보면 위와 같은 결과가 나오게 됩니다.

왜 그런지를 이해하고 위해선 JVM 메모리에 대한 이해가 필요 합니다.

 

위에서 설명을 한 내용하고 비슷합니다.

 

자바에서 new 는 객체를 생성할 때 사용합니다.

new 를 사용하면, Heap Memory에 객체를 생성을 하는 것이다

위 코드를 보면 한개는 new 를 썻고, 한개는 new 를 쓰지 않았다

 

다시 설명을 하자면

new를 사용하지 않고, 변수를 선언한 경우에는

Heap 메모리에 변수가 저장되지 않고

JVM 에 String 변수를 저장할 LiteralPool Memory 에 따로 저장이 됩니다.

 

보통 객체 같은 경우에는

Stack 메모리에 객체의 주소가 저장되어 있고

Heap 메모리에 객체의 값이 들어가 있습니다.

 

위 설명을 보고 차이를 보자면, 일반적으로

== 비교연산자를 통해서 비교를 하면,

== 비교 연산자는 Stack 메모리를 비교합니다.

그러므로 == 연산자를 통해서 비교를 하면은 주소가 다르니

false

 

가 나옵니다

 

그러나 equals 메소드를 통해서 비교를 해보면

equals 메소드는 Heap 메모리의 값을 직접 비교를 합니다.

그러면 결과는

true

가 나오게 됩니다.

 

문자열을 비교할때는 Stack 이 아닌 Heap 영역을 봐야하기 때문에

'==' 연산자는 사용하지 않는 것이 좋고, equals() 메소드를 사용해야합니다.

 

또 다른 방법으로 문자열을 비교하는 방법은

'compareTo()' 메소드를 이용하면 됩니다.

문자열을 사전순으로 비교하며, 두 문자열이 같으면 0을 반환하고,

비교 대상 문자열이 기준 문자열보다 작으면 음수를 크면 양수를 반환합니다.

위 방법은 문자열을 대소를 비교하는 것 입니다. 어떤 문자열이 더 크고 작은지

String str1 = "abc";
String str2 = "abc";
String str3 = "abcd";

System.out.println(str1.compareTo(str2));
System.out.println(str1.compareTo(str3));

 

0
-1

 

위 결과를 반환하게 됩니다.

 

 

이상입니다. 틀린 내용이 있을시 지적해주세요 감사합니다.

728x90