본문 바로가기

IT관련/자바

자바(JAVA) - String 비교 equals(), String pool

해당 내용은 주관적인 생각을 적은 내용입니다.

정확하지 않을 수 있으며 틀린 곳이 있을 수 있습니다.

 

자바에서는 String 자료형의 값을 비교하기 위해서는

String 클래스의 equals() 메서드를 사용하여 비교한다.

 

그 이유는 무엇일까?


JVM에서는 메모리관리를 위해 많은 노력을 한다.

 

예를 들어보자

String strEx1 = "데이터";
String strEx2 = "데이터";
String strEx3 = "데이터";
String strEx4 = "데이터";
String strEx5 = "데이터";

위와 같이 String 자료형을 5개를 만들어 같은 값을 넣었을 때

 

JVM에서는 자동 박싱을 통하여 객체를 생성한다.

 

아래와 같이 말이다.

String strEx1 = new String("데이터").intern();
String strEx2 = new String("데이터").intern();
String strEx3 = new String("데이터").intern();
String strEx4 = new String("데이터").intern();
String strEx5 = new String("데이터").intern();

.intern() 메서드의 경우는 눈에 보이지 않고 JVM이 자동으로 붙여서 사용한다.

 

그러면 아래와 같이 사용하였을 때는 과연 결과는 어떻게 나올까?

if ( str1 == str2) {
	System.out.println("true 입니다");
} else {
	System.out.println("false 입니다");
}

참조 자료형을 equals()로 비교하지 않아 결괏값은 "false입니다"가 나올 것 같으나,

 

결과는 "true 입니다"가 나온다

 

그 이유는 메모리를 효율적으로 관리하기 위해 JVM에서 상수 리터럴을 String 자료형 변수에 할당하였을 경우

 

JVM에서는 String pool 영역에 값을 저장시킨 후

 

같은 자료형 다른 변수에 같은 값을 저장 시키면 String pool 안에 있는 주소를 참조시키기 때문이다.

 

그리고 String 자료형에 리터럴 값을 넣었을 경우 우리 눈에는 보이지 않지만

 

메서드 뒤에. intern()이라는 메서드가 자동으로 붙게 된다.

 

intern() 메서드를 사용하게 되면 JVM이 알아서

String 자료형을 String pool 담아 값을 저장하고 사용하게 된다.

 

아래는 intern() 메서드 확인 예제이다

String strEx1 = "데이터";
String strEx2 = "데이터";
String strEx3 = strEx1.intern();
System.out.println(strEx3);

>>> 데이터

그러면 과연 변수의 주소는 어떻게 될까?

System.out.println(System.identityHashCode(strEx1));
System.out.println(System.identityHashCode(strEx2));
System.out.println(System.identityHashCode(strEx3));
		
>>> 249515771
>>> 249515771
>>> 249515771

참 조형인 String형을 리터럴로 값을 대입하였는데 같은 주소가 나온다.

그리고 intern() 메서드를 사용하여 값을 대입하여 출력해 보아도 같은 주소가 나온다.

 

즉 위의 변수 3개는 같은 주소를 가리키고 있으며,

String pool 안에 저 주소에는 "데이터"라는 값이 저장되어있다는 것이다.

 

그러면 자동 박싱이아닌 직접 객체를 new를 사용하여 객체를 생성한다면 어떻게 될까?

String strEx1 = new String("데이터");
String strEx2 = new String("데이터");
String strEx3 = strEx1.intern();

이렇게 생성하여도 주소는 위와 같이 나올까?

 

출력하였더니 결과는

>>> 249515771

>>> 796533847

>>> 1449621165

 

3개 모두 다른 주소 값이 나왔다.

 

		String strEx1 = new String("데이터");
		String strEx2 = new String("데이터");
		String strEx3 = strEx1.intern();
		
		System.out.println(System.identityHashCode(strEx1));
		System.out.println(System.identityHashCode(strEx2));
		System.out.println(System.identityHashCode(strEx3));
		if (strEx1 == strEx2) {
			System.out.println("true 입니다");
		} else {
			System.out.println("false 입니다");			
		}

그렇다면 해당 내용을 아까와 같이 ==으로 비교했을 때 결과같이 어떻게 나올 것 같은가?

 

결론은 "false입니다"가 출력이 된다.

 

String pool에 있는 값을 참조할 때는 같은 주소였지만

객체를 각각 생성하여 다른 주소에서 값을 가지고 있기 때문에 맞지 않다고 나오는 것이다

String strEx1 = new String("데이터");
String strEx2 = new String("데이터");
String strEx3 = strEx1.intern();
String strEx4 = strEx3.intern();
        
if (strEx1.equals(strEx2)) {
	System.out.println("true 입니다");
} else {
	System.out.println("false 입니다");			
}
        
if (strEx3.equals(strEx4)) {
	System.out.println("true 입니다");
} else {
	System.out.println("false 입니다");			
}

그렇다면 equals()를 통해 값을 비교했을 때는 어떻게 출력이 될 것 같은가?

 

출력 결과는 모두 "true입니다"가 출력이 된다.

 

equals() 메서드를 사용하게 되면 참조하는 주소 값이 달라도 데이터 값을 비교하게 되므로

String pool에 있으나 객체로 생성해서 비교하나 똑같이 데이터 값만을 가지고 비교할 수 있게 된다


결과적으로는 equals()를 통해 리터럴의 값을 비교할 수 있으므로

어떠한 경우에든 그냥 equals()만을 사용하는 것이 좋을 듯하다