String 비교에 대해서

이번 포스팅은 String 타입끼리의 비교에 대해서 포스팅 해보겠습니다.
일단 DataType에 대해서 간단하게 얘기하자면, DataType은 두가지 타입으로 나뉩니다.

primitive Type

primitive Type은 기본으로 제공되는 dataType으로

  • int (Wrapper class = Integer)
  • float (Wrapper class = Float)
  • double (Wrapper class = Double)
  • long (Wrapper class = Long)
  • character (Wrapper class = Character)
  • short (Wrapper class = Short)
  • byte (Wrapper class = Byte)
  • boolean (Wrapper class = Boolean)

이렇게 총 8가지 타입이 있습니다.

reference Type

primitive Type을 제외한 모든 자료형이 referenceType으로 지정됩니다.
primitive Type과 reference Type의 차이점은
primitive Type은 바로 값을 가르킨다면, reference Type은 값을 바라보는 것이 메모리에 올라가있는 주소값을 참조하게 됩니다.

reference Type은 primitive Type 8가지를 제외한 모든 자료형입니다.

이 두가지 타입은 비교를 할 때도 다릅니다.
primitive Type은 서로의 값을 비교합니다.
그러나 reference Type은 서로의 주소값을 비교하게 됩니다.
String은 reference Type이기 때문에, ==비교연산자를 사용하게되면 주소값을 비교하게 됩니다.

1
2
3
4
5
String fiTest = new String("hello");
String seTest = new String("hello");
System.out.println(fiTest==seTest);
// 출력결과 => false

두 String은 hello라는 문자열을 가지고 있지만 new String()으로 새로 생성을 한 것이기 때문에 주소값이 다릅니다.
그러나 보통은 new String으로 선언하지않고 String xxx = “문자열”; 이런식으로 리터럴형식으로 생성하게 됩니다.
이 때의 결과는

1
2
3
4
5
String fiTest = "hello";
String seTest = "hello";
System.out.println(fiTest==seTest);
//출력결과 => true

이 때는 true가 출력됩니다. 이렇게 리터럴 형식으로 같은문자열을 선언했을 때는 주소값이 같아집니다. 그 이유는,
String fiTest = “hello”; 처럼 리터럴형식으로 String을 선언할 때 String타입을 생성 후 intern(); 메소드를 호출합니다.
intern메소드는 현재 메모리상에 올라와있는 String들의 값들과 현재 선언된 String의 값을 비교하여 같은값이 있을때는 그 값이 있는 주소값을
같이 사용하게 됩니다.

위의 코드를 예로 들면, String fiTest가 hello라는 값으로 먼저 메모리에 올라가게 됩니다.
이 때도 intern()메소드를 호출은 하지만 같은 값이 없기때문에 새로운 주소값을 가지게 됩니다.
그 후 String seTest를 선언할 때도 intern()메소드가 호출됩니다.
이 때 fiTest의 값과 seTest의 값이 같기때문에 seTest는 fiTest의 주소값을 바라보게 됩니다.
이렇게 되면 주소값이 같아지기 때문에 ==연산자로 비교해도 true가 출력되게 됩니다.

같은 주소값을 바라보게 되면 seTest의 값을 바꿀 때 fiTest의 값도 같이 바뀌게 되는것이 아닌가??라는 생각을 할수도 있는데,그렇지 않습니다.
만약 seTest의 값을 선언후에 바꾸게 된다면 값을 바꾸는 것이 아니라 새로 String을 선언하는 것과 마찬가지가 됩니다.
그러면 그 이전에 선언되어있던 seTest는 Garbage Collector의 대상이 됩니다.

이런 referenceType의 비교형식과 String, StringBuffer, StringBuilder같이 다양한 문자열 타입이 있기때문에
문자열들끼리의 비교는 equals() 메소드를 쓰게됩니다. equals() 메소드는 주소값이 아닌 String의 값들을 비교하게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

이것이 우리가 흔히 쓰는 equals() 메소드의 로직입니다.
이렇게 equals비교의 값들끼리 한글자 한글자씩 비교를 하여 값이 전부 일치할 때 true를 반환하게 됩니다.
equals() 메소드도 가장 위에서 주소값을 비교하여 주소값이 같으면 true를 리턴하게 됩니다.

Share