Java '=='연산자와 equals() 메서드의 차이

Java String Pool

java에서 String 객체를 비교할 땐equals()메서드를 쓴다.
'==' 연산자와 equals()의 차이를 알아볼 것이다.
일단 그 전에 String Pool 이란 것을 먼저 알아보자!


String Pool

아래 코드는 String 객체를 만드는 두가지 방법을 모두 써서 만들어 봤다.

public class JavaStringPool {
 
    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = "Hello";
        String s3 = new String("Hi");
        String s4 = "Hi";
 
        s3 = s3.intern();
    }
}

java_string_pool


String 객체 생성시 new 연산자를 지양해야 할 이유

위에서 new 연산자로 String 객체를 생성하면 Heap Memory에 저장된다고 했다.
생성되는 과정을 자세히 보자.

  1. String s3 = new String("Hi");
  2. “Hi”라는 값의 문자열이 String Pool에 생성된다.
  3. 위의 단계에서 생성된 문자열을 전달하여 문자열 생성자를 호출한다.
  4. Heap Memory에 새 문자열이 생성되고 s3에 할당된다.
  5. 처음 생성된, String Pool에 있는 문자열은 쓸모없어져 가비지컬렉터에 의해 수거될 것이다.
  6. 우리는 Heap Memory에 하나의 문자열을 만들려고 했지만 결국 두 개가 생성됨.

’==’연산자와 equals()의 차이

'==' 연산자는 주솟값을, equals() 메서드는 주소에 들어있는 데이터를 비교한다.
그런데 위에서 봤듯이 문자열은 String Pool이란 개념이 있어 데이터가 같아도 주소가 다를 수 있다.
아래 코드를 보자.

public class Test {
    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = "Hello";
        String s3 = new String("Hi");
        String s4 = "Hi";
        
        System.out.println("s1의 hashCode: " + System.identityHashCode(s1));
        System.out.println("s2의 hashCode: " + System.identityHashCode(s2));
        System.out.println("s3의 hashCode: " + System.identityHashCode(s3));
        System.out.println("s4의 hashCode: " + System.identityHashCode(s4));
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
        System.out.println(s3 == s4);
        System.out.println(s3.equals(s4));
        System.out.println("###########################");
        System.out.println();
        
        s3 = s3.intern();  // Heap Memory쪽으로 참조하던걸 String Pool쪽으로!
        System.out.println("s1의 hashCode: " + System.identityHashCode(s1));
        System.out.println("s2의 hashCode: " + System.identityHashCode(s2));
        System.out.println("s3의 hashCode: " + System.identityHashCode(s3));
        System.out.println("s4의 hashCode: " + System.identityHashCode(s4));
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
        System.out.println(s3 == s4);
        System.out.println(s3.equals(s4));
    }
}

------------------------------------------------------------------
Output:

s1의 hashCode: 705927765
s2의 hashCode: 705927765
s3의 hashCode: 366712642
s4의 hashCode: 1829164700
true
true
false
true
###########################

s1의 hashCode: 705927765
s2의 hashCode: 705927765
s3의 hashCode: 1829164700
s4의 hashCode: 1829164700
true
true
true
true

hashCode를 주솟값이라 한다면,
s1 => String Pool705927765라는 주솟값을 가지고 생성됐다.

s2 => String Pool에 이미 같은 데이터가 있으므로 그 데이터의 주솟값을 참조한다.

s3 => String Pool1829164700라는 주솟값을 가지고 생성되었고, 문자열 생성자에 의해 Heap Memory에도 366712642라는 주솟값을 가지고 생성되었다.
참조는 366712642 쪽이다.

s4 => String Pool에 이미 같은 데이터가 있으므로 그 데이터의 주솟값을 참조한다.


결론

String Pool로 인해 주솟값데이터 값이 다를 수 있으므로 문자열의 데이터 값을 비교하고자 한다면 데이터 값을 비교하는 메서드 equals()를 쓰는게 안전하며.
문자열 생성시에는 Double Quotes 방법을 지향하자…


참고 사이트

주소: https://www.javastring.net/java/string/pool