1. 기본 타입

    1. int, double, boolean 같은 건 값 자체가 변수에 들어 있음
    2. 그래서 대입하면 실제 값이 복사됨
    3. 기본형에는 null이 없음(null을 대입하려고 해도 컴파일 오류)
    4. 값 자체를 저장 → 0, 0.0, false 등 기본값은 있지만 null은 아니다.
    int a = 10;
    int b = a;   // b에 a의 값(10)이 복사됨
    b = 20;
    
    System.out.println(a); // 10 (안 변함)
    System.out.println(b); // 20
    
    

    기본 타입은 “값 자체”가 이동

  2. 참조 타입

    1. 배열, 객체 같은 건 변수 안에서 실제 객체가 아니라 객체의 주소(참조값)가 들어 있음
    2. 대입하면 참조값이 복사되서, 두 변수가 같은 객체를 가리키게 됨
    3. 계산같은 것은 안됨
    4. 객체 주소를 저장 → 현재 유효한 객체를 가리키지 않으면 null 가능
    int[] arr1 = {1, 2, 3};
    int[] arr2 = arr1;
    
    arr2[0] =99;
    
    System.out.println(arr1[0]); // 99 {같은 배열을 보고 있어서 둘다 바뀜}
    System.out.println(arr2[0]); // 99
    

겉보기에 arr1을 건드리지 않았는데 값이 변하는 이유는 같은 주소값을 공유하는 사이라서 그럼

  1. String

    1. 특징
      1. 불변이다
        1. 한번 생성된 문자열을 바뀌지 않는다.
        2. 바뀐다고 느껴지는 것은 새로운 문자객체를 만든 뒤 변수 참조만 교체된다.
      2. 객체지만 기본 타입처럼 이용
          • 연산으로 이어 붙이거나, 리터럴(”Hello”)로 바로 쓸 수 있다.
      3. String Pool 관리
        1. 동일한 리터럴 문자열은 JVM의 String Pool에 저장되어 재사용된다.(참조가 재사용된다.)
        2. “Hello”라는 리터럴을 여러번 선언해도 같은 객체를 참조한다.
      4. 많은 편의 메서드 제공
        1. substring(), charAt(), indexOf(), split() 같은 메서드로 문자열 처리에 유리하다.
    2. 장점
      1. 안정성
        1. 불변이라 멀티스레드 환경에서 안전하다.
        2. 리터럴, 연산자 오버로딩, 메서드 제공으로 쓰기 쉽다.
        3. String Pool 덕분에 같은 문자열을 여러 번 만들어도 메모리를 아낄 수 있다.
    3. 단점
      1. 문자열을 자주 변경하면 매번 새로운 객체가 생겨 성능 저하 가능
        1. 이런 경우 StringBuilder나 StringBuffer를 쓰는 것이 낫다.
      2. 메모리 낭비 가능
        1. 잘못 쓰면 불필요한 문자열 객체가 많이 쌓인다.
    public class StringExample {
        public static void main(String[] args) {
            String a = "hello";
            String b = "hello";
            String c = new String("hello");
    
            System.out.println(a == b); // true (String Pool 같은 객체 참조)
            System.out.println(a == c); // false (new로 만든 다른 객체)
            System.out.println(a.equals(c)); // true (값 비교는 동일)
    
            // 불변성 확인
            String d = a.concat(" world");
            System.out.println(a); // "hello" (변경되지 않음)
            System.out.println(d); // "hello world"
        }
    }
    
    
  2. String Pool

    1. JVM안에 저장소
    2. 코드에서 리터럴 “hello”같은 걸 쓰면, 매번 새 객체를 만드는 것이 아니라 pool안에 있는 걸 재 사용해
    3. 즉, “hello”라는 문자열 리터럴이 여러 번 등장해도 하나만 저장하고 모두 그걸 참조한다.
  3. StringBuilder

    1. 특징
      1. 가변 → 문자열 내용 수정 가능
      2. 동기화 처리 x → 멀티스레드 환경에서는 안전하지 않음
      3. 빠름(불필요한 객체 생성이 없음)
    2. 장점
      1. 문자열 조작이 잦은 경우 성능 우수하다.
      2. 단일 스레드 환경에서 가장 효율적
    3. 단점
      1. 여러 스레드가 동시에 접근하면 데이터 꼬일 수 있음
    StringBuilder sb = new StringBuilder("hello");
    sb.append(" world"); // 같은 객체 안에서 수정
    System.out.println(sb); //"hello world"
    
  4. StringBuffer

    1. 특징
      1. StringBuilder와 거의 같지만 동기화 지원
      2. 멀티스레드 환경에서 안전하게 문자열 조작 가능
    2. 장점
      1. 여러 스레드가 동시에 같은 문자열을 수정해도 안전
    3. 단점
      1. 동기화 때문에 StringBuilder보다 성능이 느림
      2. 단일 스레드 환경에서는 굳이 쓸 필요 없음
    StringBuffer sbf = new StringBuffer("hello");
    sbf.append(" world"); // 같은 객체 수정(스레드 안전)
    System.out.println(sbf); // "hello world"