BackEnd/Java

[Java]컬렉션(collection) String 불변성

Hojung7 2024. 8. 12. 14:39
String이란?

 - java.lang 패키지에서 제공

 

 - 문자열을 저장하고 다루는 용도의 클래스

 

 [String 객체를 생성하는 방법]

 

 1) String s1 = "Hello";  // 리터럴 표기법을 이용한 방법

→ Heap 영역 내부에 Constant(상수) Pool에 String 객체 생성

 

 2) String s2 = new String("Hello"); // new 연산자 이용한 방법

 -> Heap 영역에 String 객체 생성

 

 [String의 불변성(immutable)]

 - String은 기본적으로 값이 변하는 것이 불가능

 

ex) String str = "abc";    // "abc" / 참조 주소 : 0x100

str += "def";     // "abcdef" / 참조 주소 : 0x300

 

 -> 참조하는 객체의 주소가 달라진다!!!

 

 [String 불변성 확인]

 

 - String 클래스에서 값을 저장하는 필드가 final

→ 상수 == 변경 불가

 

 - System.identityHashCode(참조변수)

→ 객체의 주소 값을 이용해서 생성된 해시코드

→ 모든 객체가 다른 결과를 반환

 

 - 같은 객체에 저장된 값이 변했다면 주소값은 일정해야만 한다!!!

 

 - 참조하고있던 객체가 변했다면 주소값은 변하게된다!!!

 

 [Constant Pool 확인]

 

- "" String 리터럴 표기법을 이용해 생성된 String 객체가 저장되는 Heap 내부 영역

 

 - 동일한 문자열을 생성하게 되는 경우 객체가 새롭게 생성되지 않고

기존 주소가 반환된다(재활용)

 

#예제

[dto]

package api.dto;

public class TestDto {

	private int num;
	private String str;
	
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getStr() {
		return str;
	}
	public void setStr(String str) {
		this.str = str;
	}
	
	
}

 

[service]

	public void test1() {
		
		TestDto t = new TestDto();
		
		// TestDto 객체의 주소를 이용해서 만든 해시코드 확인
		System.out.println("TestDto : " + System.identityHashCode(t));
		
		// TestDto 객체의 필드 값을 변경
		t.setNum(200);
		t.setStr("Apple");
		
		System.out.println("변경 후 TestDto : " + System.identityHashCode(t));
		
		
		System.out.println("--------------------------------------");
		
		// String 객체 생성(리터럴 표기법 이용 방법)
		String s = "Hello";
		System.out.println("String : " + System.identityHashCode(s));
		
		// s가 참조하는 객체의 값을 변경
		s += "World";
		System.out.println("변경 후 String : " + System.identityHashCode(s));
	}

 

#결과

 

#예제  [Constant Pool 확인]

[service]

public void test2() {
		
		String s1 = "Hello"; // 2055281021 (상수풀 생성)
		System.out.println("s1 : " + System.identityHashCode(s1));
		
		
		// 같은 값을 지닌 String 생성
//		String s2 = s1;
		String s2 = "Hello"; // 2055281021 (상수풀 객체 재활용)
		System.out.println("s2 : " + System.identityHashCode(s2));
		
		
		// 같은 같을 지닌 String을 new 연산자를 이용해 생성
		String s3 = new String("Hello"); // 1804094807 (Heap 새로 생성)   
		System.out.println("s3 : " + System.identityHashCode(s3));
		
		
		System.out.println("-------------------------------------------");
		
		// s1, s2는 같은 객체를 참조하고 있음
		// == s1, s2에 저장된 주소 값이 같음
		// -> equals()를 사용하지 않아도 비교 가능
		
		System.out.println("s1 == s2 : " + (s1 == s2) ); // true
		
		
		// s1, s3는 저장된 값은 같아도
		// 서로 다른 객체를 참조하고 있음
		// == s1, s3의 주소 값이 다르기 때문에 
		//    비교연산 시 무조건 false
		
		// -> 그래서 문자열 비교는 equals()로 하는게 속편함
		System.out.println("s1 == s3 : " + (s1 == s3)); // false
		
	}

 

#결과