들어가며
이번 포스트에서는 자바에서 String 에 대해 이해해 보려고합니다.
String은 기본적으로 제공되는 변수 - 원시타입들과는 다릅니다.
원시타입
기본적으로 제공 하는 변수형 들을 말합니다.
정수 : btye short int long - 1 , 2 , 4 , 8 바이트로 이루어져있습니다.
사용
저는 특별한 제약조건이 있는 경우가 아니라면 int 와 long을 사용하고 있습니다.
int의 경우 21억 정도 까지의 값들을 저장할 수 있는데 만약 저장 될 값이
20억이 넘어갈 것같은 경우에는 long으로 아닌 경우에는 int를 사용하고 있습니다.
실수 : float Double - 4 ,8
문자 : char - 2
논리 : boolean - 1
이렇게 원시타입이 이루어져 있습니다.
그리고 String은 불변하는 객체입니다.
즉, 객체에 담기는 원시타입의 변수형 , 객체 자체인 String이 있게 됩니다.
불변객체
불변 객체는 객체 생성 이후에 내부 상태가 변하지 않습니다.
일단 메모리를 할당 받고 나면 그 크기를 유지하게 되는데 새롭게 선언된 String의 경우
힙 메모리의 StringPool이라는 공간에 저장되게 됩니다.
만약 원시타입 , 혹은 참조되는 클래스의 더이상의 상속 , 변화를 금지하겠다는 의미를 넣고 싶으면
final 키워드를 통해 만들 수 있습니다.
예를 들어 스프링에서 서비스코드에서 레포지토리 클래스를 불러서 선언하면 이 이후에 서비스를 이용해 레포지토리를 직접 부르는 것을 금지하기 위해 final을 붙여서 참조하게 됩니다.
이걸 왜쓰냐 라고 하면 사실 멀티 쓰레딩을 하게되거나 동기화 , 비동기화 과정 중 공유되는 자원으로 써 선택된 경우 이 값이 변화하는 것을 주의 깊게 생각해야합니다.
만약, 값이 없어져 버리면 null 예외가 값이 넘어가면 indexOfArray 에러가 나는 것처럼 처리에 대한 깊은 고민이 필요한데 꼭 이런 생각이 필요하지 않은 부분이 있다면 final 키워드를 통해 동일한 값으로 반환되도록 하면 되기 때문입니다.
따라서 이걸 통해 예외가 발생해도 다음 메서드 실행때는 동일한 기능을 수행 시킬 수 있습니다.
근본적인 이유는 아닌데 GC - 가비지 컬렉션이 읽어야하는 객체의 수가 줄 기때문에 GC 수행시 소요시간이 줄어든다는 장점도 있습니다.
그럼 String은 왜 불변객체임?
1. 캐싱 기능에 의한 메모리 절약과 속도 향상
- Java에서 String 객체들은 Heap의 String Pool 이라는 공간에 저장되는데,
참조하려는 문자열이 String Pool에 존재하는 경우 새로 생성하지 않고 Pool에 있는
객체를 사용하기 때문에 특정 문자열 값을 재사용하는 빈도가 높을 수록 상당한 성능 향상을
기대할 수 있다.
2. thread-safe
- String 객체는 불변이기 때문에 여러 쓰레드에서 동시에 특정 String 객체를 참조하더라도 안전하다.
3. 보안기능
- 중요한 데이터를 문자열로 다루는 경우 강제로 해당 참조에 대한 문자열 값을 바꾸는 것이 불가능하기 때문에 보안에 유리하다.
출처:
https://dev-coco.tistory.com/153
[슬기로운 개발생활:티스토리]
String의 저장
String을 선언하고 사용하는 방법은 크게 두가지가 있습니다.
- new String 을 통한 선언
- “” - 리터럴을 통한 선언
두가지 방식 모두 장단점이 있는데 일단 비교하면서 생각해 보겠습니다.
어디에 저장하냐
new String - 객체로 생성 - 힙 영역에 만들어짐 - GC 에 의해 관리됨
“” - Stirng pool 이라는 메모리 영역 (힙 안에 있음) 여기에 저장됩니다.
어떻게 저장하냐
new String - 새로 계속 객체를 만들어서 저장하게 됩니다.
“” - String pool 에 있는 메모리에 기존 값이 있다면 불러주고 , 없다면 저장합니다.
→ 결국 메모리를 할당하는 것이 아닌 이미 할당 되어 있는 String pool 공간에 값을 저장한다는 의미입니다.
변경이 가능한가
둘다 불변 객체로써 생성되기 때문에 new String의 경우 새로운 객체를 생성하고 , “”의 경우 새로운 문자열 객체로 변환하여 조작합니다.
String str1 = new String("hello");
str1 = str1 + " world";
System.out.println(str1); // hello world
String str2 = "hello";
str2 = str2 + " world";
System.out.println(str2); // 오류 발생 (불변 객체)
이렇게 볼 수 있습니다. str1 이라는 공간을 새로운 객체로 생성해서 사용하기 때문에 가능하지만
str2 의 경우 기존에 저장된 String pool에 저장이 안되기 때문에 에러가 발생합니다.
동일성
당연하게도 new String은 새로운 객체를 만드는 것이기 때문에 다른 메모리 주소를 가지고 객체로써의 의미 에서는 다른 값으로 처리됩니다.
“” 로 선언된 경우에는 같은 주소로 볼 수 있습니다.
String str1 = new String("hello");
String str2 = new String("hello");
String str3 = "";
String str4 = "";
System.out.println(str1 == str2); // false (서로 다른 객체)
System.out.println(str3 == str4); // true (동일한 객체)
예를 들어 이런 식으로 하면 str1 과 str2의 메모리 주소값을 통해 비교하기 때문에 서로 다른 객체라는 것을 볼 수 있습니다.
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1.equals(str2)); // true (서로 같은 값)
이렇게 보면 equals는 그 값 자체를 비교하기 때문에 결과 값이 같다는 것을 볼 수 있습니다.
어떨 때 써야하는가?
new String : 문자열을 생성후 변경해야하는 경우, 혹은 String 풀에 저장되지 않는 특수한 문자열인 경우
“” : 자주 사용되는 경우 - 메모리를 추가로 할당하지 않기 때문에 효율적 && 문자열값 변경이 필요없는 경우
추가 - 특수한 문자열?
그냥 궁금해서 찾아봤습니다.
특수 문자열 유형 분류
- 공백 문자열:
- 하나 이상의 공백 문자 (, \\t, \\n, \\r, \\f)로 구성된 문자열
- 예시: " ", " \t", "\n\n", "\r\n\f"
- 동적 문자열:
- 변수 값, 표현식 또는 함수 호출 결과를 포함하는 문자열
- 예시: String str = "Hello " + name + "!";
- 형식 문자열:
- printf()와 같은 서식화 함수에 사용되는 문자열
- 예시: "%d-%02d-%04d"
- 특수 문자 포함 문자열:
- 따옴표 ("), 역슬래시 (), 백스페이스 (\b) 등 특수 문자를 포함하는 문자열
- 예시: "This is a "special" string."
- 대규모 문자열:
- 메모리 할당 오류를 초래할 수 있는 매우 긴 문자열
- 예시: 1MB 이상 크기의 문자열
'JAVA' 카테고리의 다른 글
JAR , WAR (0) | 2024.08.23 |
---|---|
JAVA - 객체지향에서의 디자인패턴 (0) | 2024.06.04 |
JAVA 디자인 패턴에 대하여 -개념 (0) | 2024.06.04 |
JAVA - SOLID에 대하여 (0) | 2024.06.03 |
JAVA-어노테이션에 대하여 (0) | 2024.06.03 |