본문 바로가기
Java

Java에서 String은 왜 불변일까?

by kmmguumnn 2020. 7. 21.

Java에서 String은 불변(Immutable) 객체이다.

 

불변 객체란 무엇일까?

불변 객체란, 객체가 생성된 후 내부의 상태가 변하지 않고 계속 유지되는 객체를 말한다. 즉, 변수에 객체가 한 번 할당되면, 해당 객체의 참조를 변경할 수도, 내부의 상태를 수정할 수도 없는 것이다.

 

Java에서 String 객체는 immutable, 즉 '불변성'이라는 특성을 가지는데, Java 언어를 디자인한 사람들은 왜 그런 선택을 한 것일까? 크게 5가지 이유를 생각해 볼 수 있다.

 

 

1. String Pool

String이 불변이기 때문에 String Pool도 존재할 수 있다.

어떤 프로그래밍 언어라도 String 타입은 매우 빈번하게 사용된다. 그래서 Java에서는 String Pool이라는 공간에 String을 포함시켜서, 매번 String 객체를 새로 생성하기보다는 값이 같은 String이라면 String Pool에 있는 객체를 재사용할 수 있도록 구현했다.

 

값이 같은 String은 String Pool 내에서 String 객체를 공유하도록 한 것이다. 그런데 공유를 하려면 String은 반드시 immutable, 즉 불변이어야 한다. mutable하다면 두 객체의 공유는 불가능하다.

 

String s1 = "Java"; 
String s2 = "Java"; 

위 예시에서 s1과 s2는, "Java"라는 value를 갖는 String Pool 내부의 하나의 String 객체를 바라보고 있다. 이 때 s1의 값을 "C++"로 바꾼다면 s1은 String Pool 내부의 다른 String 객체를 바라보게 된다.

 

하지만 만약 String이 mutable하다면?  s1의 값만 "C++"로 바꿀 수 있고 s2는 그대로 "Java"로 남아있게 되는 셈인데, 값이 다른데 같은 참조를 가진다는 것은 말이 안된다. 즉 String 타입이 mutable하다면, String 객체끼리의 공유는 불가능하게 된다.
(실제로는 s1을 "C++"로 바꾸면, String Pool에 이미 "C++" 값을 가진 객체가 있으면 그 객체를 참조하고, 없다면 String Pool에 새로운 객체를 생성한다.)

 

결국 Java에서는 String pool을 구현하기 위해 String을 immutable한 객체로 만들어야 했던 것이다.

 

 

2. 보안

Java에서 메서드의 파라미터로 String을 받는 경우는 매우 흔하다.

예를 들어 사용자의 이름이나 패스워드, 혹은 네트워크 연결을 위한 포트 번호나 connection URL, 파일 이름 등 중요한 정보를 String으로 받을 때가 많다. JVM의 class loader가 class loading을 수행할 때도 마찬가지다.

 

메서드의 인자로 String 타입을 받는 간단한 예를 들면 이런 식이다.

void criticalMethod(String userName) {
    // perform security checks
    if (!isAlphaNumeric(userName)) {
        throw new SecurityException(); 
    }

    // do some secondary tasks
    initializeDatabase();

    // critical task
    connection.executeUpdate("UPDATE Customers SET Status = 'Active' " +
      " WHERE UserName = '" + userName + "'");
}

 

그런데 String이 mutable하다면, 메서드의 인자로 받은 값은 메서드의 caller(호출자)에 의해 언제든지 바뀔 수 있게 된다. 이는 보안상 엄청난 취약점을 발생시킨다.

 

 

3. 동기화 (Synchronization)

객체가 불변이면 멀티 스레드 환경에서도 값이 바뀔 위험이 없기 때문에, 자연스럽게 thread-safe한 특성을 갖게 되고, 동기화와 관련된 위험 요소에서 벗어날 수 있다. 여러 스레드에서 동시에 접근해도 별다른 문제가 없다.

 

또한 String의 경우 한 스레드에서 값을 바꾸면, 해당 객체의 값을 수정하는 것이 아니라 새로운 객체를 String Pool에 생성한다. 따라서 thread-safe하다고 볼 수 있다.

 

 

4. Hashcode Caching

String의 hashCode() 메서드 구현을 보면, 아직 hash 값을 계산한 적이 없을 때 최초 1번만 실제 계산 로직을 수행한다. 이후부터는 이전에 계산했던 값을 그냥 리턴만 하도록 되어 있다. 즉 hashCode 값을 캐싱(caching)하고 있다.

String.hashCode()

 

이렇게 caching이 가능한 것도 결국 String이 불변이기 때문에 얻을 수 있는 이점이다.

 

hashCode() 메서드는 Hash 자료구조의 구현체, 예를 들면 HashMap, HashTable, HashSet와 같은 클래스에서 꽤 자주 호출된다. String 객체와 함께 Hash 구현체를 사용하는 경우라면 이러한 caching 덕분에 성능상 큰 이점을 볼 수 있을 것이다.

 

 

5. 성능

위에서 나온 내용들을 몇가지 종합해보면, String이 불변성을 가짐으로써 "성능"이라는 측면에서 유리하다는 것을 알 수 있다. String은 상대적으로 자주 쓰이는 타입이기 때문에, String의 성능을 개선하는 것은 전체 애플리케이션의 성능에도 긍정적인 영향을 주게 된다.

 

 


 

References

 

Why String is Immutable in Java? | Baeldung

Explore why Strings in the Java language are immutable.

www.baeldung.com

 

Why String is Immutable or Final in Java

A blog about Java, Programming, Algorithms, Data Structure, SQL, Linux, Database, Interview questions, and my personal experience.

javarevisited.blogspot.com

 

Why is String immutable in Java?

I was asked in an interview why String is immutable I answered like this: When we create a string in java like String s1="hello"; then an object will be created in string pool(hello) and s1 w...

stackoverflow.com

 

Java에서 String 클래스가 왜 final 혹은 Immutable인가? | Mimul Tech log

Java에서 String이 왜 final 혹은 Immutable인지에 대해서 적당한 사유를 정리해 준 사이트(Why String Class is made Immutable or Final in Java - 5 Reasons) 번역.

www.mimul.com

 

 

'Java' 카테고리의 다른 글

String Constant Pool이란? | Java String Pool  (2) 2020.07.20
JVM 아키텍처 / Garbage Collection  (0) 2019.04.05
JVM, JRE, 그리고 JDK의 개념  (0) 2019.02.04
POJO 이해하기  (0) 2018.12.12

댓글