[Java] String에 관한 고찰

Hyeon-Uk·2022년 10월 25일
0
post-thumbnail

String이란?

  • 자료의 형태를 표시하는 자료형중 하나
  • 문자열이며, 이는 연속된 문자들을 뜻한다.
  • Java에서 String은 원시타입(ex int, long ....) 이 아닌 객체이다.
  • 따라서 new를 통해 생성을 할 수 있다.

String 선언방법

String str1 = "Hyeon Uk";
String str2 = new String("Hyeon Uk");

String 비교방법

String타입의 변수들을 비교하기 위해서는 어떻게 해야할까?
정수타입과 같은 원시타입의 변수를 비교하기 위해서는 == 연산자를 이용하면 된다.

int a = 10;
int b = 10;
System.out.println(a==b); // true

그럼 String타입의 변수도 위와같이 == 연산자를 통해서 비교를 해보자

String str1 = new String("Hyeon Uk");
String str2 = new String("Hyeon Uk");
System.out.println(str1==str2);

결과는 무엇이 나올까? 답은 false이다.

Why??

위에서 말했듯이 String 타입의 변수는 원시타입이 아닌 "객체"이다.
객체에서 == 연산자를 사용하면 객체의 값이 아닌, 객체의 주소값을 비교하게된다.
str1과 str2가 할당받은 heap의 주소가 다르기때문에, 내용이 같은 "Hyeon Uk"이라고 하더라도 주소값이 다르기때문에 false라는 결과를 반환하게 되는것이다.
따라서 String객체의 값을 비교하기 위해서는 아래와 같은 .equals() 메서드를 사용해서 비교를 해야한다.

System.out.println(str1.equals(str2)); // true

그렇다면?

String 타입의 변수 선언방법은 기본적으로 2가지가 있다고 했다. 그렇다면 아래와 같은 코드의 결과값은 어떻게 나올것인지 한번 생각해보자. (코드 돌려보지말고 한번 생각해보자)

String str1 = new String("Hyeon Uk");
String str2 = "Hyeon Uk";
String str3 = "Hyeon Uk";

System.out.println(str1.equals(str2)); // ?
System.out.println(str1 == str2); // ?
System.out.println(str2 == str3); // ?

고민에 대한 대답은 아래와 같다.

"엥? String은 객체타입이라며? 1번째,2번째는 알겠는데 왜 3번째는 true야??"

문자열 상수풀??

다른 언어는 구체적으로 어떻게 동작하는지에 대해 잘 모른다. 하지만 JVM에서는 문자열에 대해 문자열 상수풀이라는 Heap영역의 특별한 공간이 존재한다.

  • new를 사용해서 문자열을 할당받으면, 문자열 상수풀이 아닌 Heap영역에 할당이 된다.

  • 리터럴 상수를 이용하여 문자열을 생성하면 두가지 경우가 있다.

    1. 문자열 상수풀에 해당 문자열 상수가 존재하는 경우
    2. 문자열 상수풀에 해당 문자열 상수가 존재하지 않는 경우

    str2와 같이 상수풀에 존재하지 않는 문자열을 할당받으려 하는경우, 상수풀에 해당 문자열을 할당한 뒤, 참조시켜준다.
    str3와 같이 상수풀에 존재하는 문자열을 할당받으려 하는경우, 상수풀에 존재하는 문자열의 주소를 참조시켜준다.

위를 눈으로 확인해보기 위해 String의 주소들을 모두 찍어보았다.

String str1 = new String("Hyeon Uk");
String str2 = "Hyeon Uk";
String str3 = "Hyeon Uk";

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

결과는 아래와 같이 str2와 str3는 같은 문자열 상수풀에 있는 주소를 참조하고 있으므로 주소가 같고, str1은 new로 할당받았기 때문에 str2와 str3의 주소와 다른것을 볼 수 있다.

그렇다면?

"str2와 str3가 같은 주소를 참조하고 있으니, str2의 내용을 바꾸면 str3의 내용도 같이 바뀌겠지??"

답은 아니다. 한번 눈으로 직접봐보자

String str1 = new String("Hyeon Uk");
String str2 = "Hyeon Uk";
String str3 = "Hyeon Uk";

String str1Replace = str1.replace("Uk","UUUUUKKKK");
str2 = str2.replace("Uk","UUUUUKKKK");

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

System.out.println(System.identityHashCode(str1));
System.out.println(System.identityHashCode(str1Replace));
System.out.println(System.identityHashCode(str2));
System.out.println(System.identityHashCode(str3));

위의 코드의 결과이다

new 로 할당받은 객체의 String값을 바꾼다고, 문자열 상수풀의 값을 바꾼다고해서 해당메모리의 주소의 값을 변경하는것이 아닌, 새로 업데이트 되는 String의 값을 할당한 뒤, 업데이트된 주소로 참조값을 바꾸기 때문에 위와같은 결과가 나타나게 되는것이다.

결론

이렇게 눈으로 보면서 동작원리를 알아내고 찾아보는 재미를 느끼게 되어서 즐거웠습니다😀

profile
Hi🖐

0개의 댓글