불변 == 읽기 전용 클래스

사이드 이펙트와 참조자

  • 특정 인스턴스에 대한 참조는 여러 개가 될 수 있으며 이를 막을 수도 없음
    • 매개변수, 멀티스레딩 환경
  • 모든 참조는 대상 인스턴스에 대한 읽기, 쓰기, 접근(Mutable)이 모두 허용
    • 참조자 및 메서드 통한 필드 값 변경을 제어할 수 있는 문법 없음
  • 인스턴스에대한 무결성을 보장해야하는 구조에서 (논리적) 문제가 발생할 수 있음

불변 객체의 정의

  • 모든 필드를 final 선언함으로써 상수화한 클래스 (무결성)
    • 필드 초깃값을 기술할 수 있는 부분 제외(생성자 또는 초깃값 정의)
  • 필드 값을 변경해야 한다면 새로운 사본 인스턴스를 생성하면서 원하는 수정된 초기값을 기술해 반환하는 구조로 개발(원자성 보장)
    • 비효율적일 수 있으나 멀티스레딩 환경에서 장점 존재
  • 대표적 불변 객체
    • String, Wrapper class

문자열 상수와 String

  • 문자열의 본질은 문자 배열이며 문자열은 인코딩 규칙에 영향을 받음
    • char[], String
    • 문자 배열은 겹따온표를 이용한 리터럴 표기 가능
    • Java 9 이후 char[]에서 byte[] 로 변경
  • String 클래스는 불변 클래스이며 논리적 의미로 기본 형식에 속하는 특성을 보임
    • 덧셈 연산의 결과로 임시 객체가 생기는 문제가 있음
    • 큰 문자열을 다룰 경우 효율이 더 떨어짐

문자열은 가변일 수 있는데 배열로 표현한다?

이번 섹션 3강 매우 내용이 좋다. 문자열끼리 연산의 오버헤드를 잘 설명해줌!

문자열 비교

  • 상등 연산으로 두 String 클래스 인스턴스를 비교할 경우 심각한 논리적 문제가 있을 수 있다
    • 문자열 상수 풀
    • JVM이 클래스 로딩 시 미리 인스턴스 생성
  • equals() 를 쓰거나 compareTo() 로 문자열 비교하는 것이 적절

Java(JVM)가 문자열을 관리하는 구조

모든 문자열은 상수 풀로 관리

  • C/C++ 로 개발된 PE 파일과 유사한 구조
    • .exe 파일의 내부에 문자열이 포함
    • 실행 코드가 저장되는 정적 메모리 영역에 문자열 상수 저장
    • 같은 문자열 상수에 대한 포인터의 주소는 모두 동일
  • 코드상 존재하는 모든 문자열 상수(리터럴)은 Class가 로딩될 때 Runtime constant pool 에 등록된 후 힙 영역에 존재하는 String constant pool 에도 추가(String객체)

String.intern()

public native String intern();

  • native 는 C/C++로 구현된 메소드에 붙이는 예약어
    • 문자열 상수 선언 시 내부적으로 intern() 함수 호출
    • String s1 = “Hello”;
  • 문자열 상수 풀에서 문자열을 조회하고 ‘무조건’ 반환
    • 문자열 상수와 일치하는 문자열을 상수 풀에서 검색
    • 찾으면 이미 생성되어 있는 String 인스턴스 반환
    • 없으면 새로 String 객체 생성 후 풀에 추가하고 반환
    • 문자열 상수 풀은 힙 영역(Java 7 이후)에 속하며 GC 대상

두 개의 상수 풀

A string literal is always of type String

  • .class 파일 Constant pool 에 저장(컴파일)
  • Runtime constant pool로 이동(로딩)
  • String costant pool로 이동(실행)

내용을 변경하는 StringBuilder

  • 불변 객체인 String 의 단점을 해결하기 위해 만들어진 가변 String
  • 문자열 값 변경시 임시 객체 만들지 않고 인스턴스 데이터 직접 수정
    • append()
    • insert()
    • delete()
    • reverse()
    • toString()

래퍼 클래스

  • 기본 데이터 형식은 클래스가 아니므로 메소드를 가지지 못함
  • 이 문제 해결하기 위해 기본 데이터 형식으로 클래스로 만든 것이 Wrapper class
    • Byte, Character, Short, Integer, Long, Float, Double, Boolean

박싱과 언박싱

  • 기본 형식을 래퍼 클래스로 만드는 경우가 박싱
    • Character obj = new Character(‘A’);
    • Integer obj = new Integer(123);
    • Integer obj = new Integer(“123”);
    • Integer obj = Integer.valueOf(“123”);
    • Integer obj = 123;
  • 래퍼 클래스에서 기본 데이터 값을 얻는 것이 언박싱