ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] String이 불변 객체인 이유는?
    Java/자바를 더 깊게 2022. 2. 15. 01:19

    보통 String / StringBuffer / StringBuilder의 차이점들은 많이 알고 있습니다.

    String은 불변 객체이며, StringBuffer/ StringBuilder는 가변 객체입니다.

    또한 StringBuilder는 thread-safe 하지 않으며 StringBuffer는 thread-safe 합니다.

     

    그런데 String은 왜 불변 객체로 만들었을까요?

    1. 성능

    자바에서 문자열은 정말 많이 사용됩니다.

    따라서 자바는 상수풀 이라는 것을 만들었습니다.

    public class Test {
        public static void main(String[] args) {
            String s1 = "Hello World";
            String s2 = "Hello World";
    
            System.out.println(s1 == s2);  // true
        }
    }

    위의 코드 실행 과정을 분석해보면 문자열 s1에 해당하는 것을 상수 풀에서 검색합니다.

    만약 상수 풀에 없다면 상수 풀에 등록하고 해당하는 레퍼런스 값을 반환합니다.

    s2 문자열도 마찬가지로 상수 풀에서 해당 문자열이 있는지 검색합니다.

    s1을 이미 상수 풀에 등록했기 때문에 같은 레퍼런스를 반환합니다.

     

    이렇게 문자열을 캐싱하고 재사용하면 힙 공간을 많이 절약할 수 있습니다.

    https://devlog-wjdrbs96.tistory.com/247

     

    다음 코드의 결과는 어떻게 될까요?

    String str1 = new String("hello")
    String str2 = String("hello")
    System.out.println(str1==str2)

    힙 영역에서 서로다른 주소를 가리키고 있기 때문에 false가 나오게 됩니다.

    따라서 new 키워드를 사용하는것은 메모리가 낭비되기 때문에 좋지 않습니다.

     

    이렇게 상수 풀을 사용하는데 String이 가변 객체라면 어떻게 될까요?

    public class Test {
        public static void main(String[] args) {
            String s1 = "Hello World";
            String s2 = "Hello World";
            s1 = "changed";
    
            System.out.println(s1 == s2);  // true
        }
    }

    String이 불변 객체가 아니면서 상수 풀을 사용하고 있다면 위의 결과도 true가 나오게 될 것입니다.

    이것은 말이 안되기 때문에 상수 풀의 장점을 얻어 사용하기 때문에 String을 불변 객체로 만들었습니다.

     

    2. 동기화

    불변 객체는 값이 바뀔 일이 없기 때문에 멀티스레드 환경에서 Thread-safe 하다는 장점이 있습니다.

    따라서 일반적으로 불변의 객체는 동시에 실행되는 여러 스레드에서 공유할 수 있습니다.

    스레드가 값을 변경하면 동일한 문자열을 수정하는 대신 문자열 풀에 새 문자열이 생성되기 때문에 스레드 안전을 보장합니다.

     

    3. 해시코드 캐싱

    문자열 객체는 데이터 구조로 많이 사용되기 때문에 해시 맵, 해시 테이블, 해시 셋 등과 같은 해시 구현에서도 널리 사용됩니다.

    이러한 해시 구현에 따라 작동할 때 버킷을 위해 hashCode() 메서드가 자주 호출됩니다.

    public final class String {
        public int hashCode() {
            int h = hash;
            if (h == 0 && value.length > 0) {
                char val[] = value;
    
                for (int i = 0; i < value.length; i++) {
                    h = 31 * h + val[i];
                }
                hash = h;
            }
            return h;
        }
    }

    String의 hashCode()메서드 구현을 보면 hash값을 계산한 적이 없을 때 최초 1번만 실제 계산 로직을 수행 합니다.

    이후부터는 h==0이 아니면 해당 값을 그냥 리턴만 하도록 되어 있습니다.

    String이 불변 객체이기 때문에 이렇게 캐싱이 가능하다는 이점을 활용할 수 있습니다.

    따라서 문자열 객체로 작동할 때 해시 구현을 사용하는 컬렉션의 성능을 향상할 수 있습니다.

     

    4. 보안

    문자열은 Java 애플리케이션에서 사용자 이름, 암호, 연결 URL, 네트워크 연결 등과 같은 중요한 정보를 저장하는 데 널리 사용됩니다.

    클래스를 로드하는 동안 JVM 클래스 로더에서도 광범위하게 사용됩니다.

    따라서 String 클래스 보안은 일반적으로 전체 응용 프로그램의 보안에 매우 중요합니다.

    public class Test {
        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 + "'");
        }
    }

    if문을 통하여 필요한 모든 보안 검사를 수행하여 문자열이 AlphaNumeric인지 확인하는 작업을 수행합니다.

    AlphaNumeric : 라틴문자와 아라비아 숫자의 합성어

     

    만약에 String이 불변 객체가 아니라면 메서드를 호출했던 클라이언트는 String에 대한 참조가 메서드를 호출한 이후에도 남아있습니다.

     

    따라서 보안 검사를 실시한 이후에도 이 문자열이 안전하다고 보장할 수 없습니다.

    메소드를 호출했던 클라이언트가 String에 대한 참조를 계속 가지고 있기 때문에 문자열을 변경할 수 있다는 가능성이 남아있습니다.

    이 경우 SQL injection이 쉽게 수행될 수 있으며 보안 성능이 저하될 수 있습니다.

     

    이러한 이유들로 Java에서는 String을 불변 객체로 만들었습니다.

     

    주의할 점

    앞서 말한 불변 객체라는 특징을 가지고 있기 때문에 String에 연산을 하게 되면 새로운 객체가 만들어지게 됩니다.

    이런 비효율을 막기 위해서는 StringBuilder, StringBuffer를 이용해야 합니다.

     

     

     

    출처

    https://devlog-wjdrbs96.tistory.com/247

     

    [Java] String이 불변 객체인 이유는 무엇일까?

    String이 불변 객체인 이유 String 객체가 불변 객체 라는 것은 다들 알고 있을 것입니다. 불변 개체는 완전히 생성된 후에도 내부 상태가 일정하게 유지되는 개체입니다. 즉, 객체가 변수에 할당되

    devlog-wjdrbs96.tistory.com

     

    댓글

Designed by Tistory.