JAVA 불가 변류기 (immutable) 메커니즘 과 String 의 불가 변성

5984 단어 자바
1. 불가 변 류 안내
가 변 하지 않 는 클래스: 가 변 하지 않 는 클래스 란 이러한 인 스 턴 스 가 생 성 되면 구성원 변수 값 을 바 꿀 수 없다 는 것 을 말 합 니 다.예 를 들 어 JDK 내부 에 자체 적 으로 가지 고 있 는 많은 가 변 류: Interger, Long, String 등 이다.가 변 클래스: 가 변 클래스 에 비해 가 변 클래스 가 인 스 턴 스 를 만 든 후에 구성원 변 수 를 바 꿀 수 있 습 니 다. 개발 에서 만 든 대부분의 클래스 는 가 변 클래스 에 속 합 니 다.
2. 불가 변류의 장점
가 변 류 와 가 변 류 의 차 이 를 말 하면 우 리 는 왜 가 변 류 가 있어 야 하 는 지 더 알 아야 한다.이런 특성 이 JAVA 에 게 어떤 이점 을 가 져 다 줍 니까?
  • 스 레 드 안전 불 가 변 대상 은 스 레 드 가 안전 하고 스 레 드 간 에 서로 공유 할 수 있 으 며 특수 체 제 를 이용 하여 동기 화 문 제 를 확보 할 필요 가 없다. 대상 의 값 이 바 뀌 지 않 기 때문이다.오류 가 발생 할 가능성 을 낮 출 수 있 습 니 다. 잠 금 장치 등 으로 메모리 의 일치 성 을 확보 할 필요 가 없 기 때문에 동기 화 비용 도 줄 일 수 있 습 니 다.
  • 구조, 사용 과 테스트 하기 쉽다
  • ...

  • 3. 불가 변 류 의 디자인 방법
    디자인 불가 변 류 에 대해 개인 은 다음 과 같은 원칙 을 요약 한다.
    1. 클래스 에 final 장식 부 호 를 추가 하여 클래스 가 계승 되 지 않도록 보증 합 니 다.만약 에 클래스 가 계승 되면 클래스 의 불가 변성 체 제 를 파괴 할 수 있 습 니 다. 계승 류 가 부모 류 를 덮 는 방법 과 계승 류 가 구성원 변수 값 을 바 꿀 수 있다 면 하위 클래스 가 부모 류 의 형식 으로 나타 날 때 현재 클래스 가 변 할 수 있 는 지 여 부 를 보장 할 수 없습니다.
    2. 모든 구성원 변 수 는 개인 적 이 어야 하 며 final 수식 을 추가 하여 이러한 방식 으로 구성원 변 수 를 바 꿀 수 없 도록 확보한다.그러나 이 정도 만 으로 는 부족 하 다. 대상 구성원 변수 라면 외부 에서 값 을 바 꿀 수 있 기 때문이다.그래서 네 번 째 는 이 부족 함 을 보완 한다.
    3. 구성원 변 수 를 바 꾸 는 방법 을 제공 하지 않 습 니 다. setter 는 다른 인 터 페 이 스 를 통 해 구성원 변수의 값 을 바 꾸 지 않 고 가 변 적 인 특성 을 파괴 하지 않도록 합 니 다.
    4. 구조 기 를 통 해 모든 구성원 을 초기 화하 고 딥 카피 (deep copy)
    만약 에 구조 기 가 들 어 오 는 대상 이 구성원 변수 에 직접 값 을 부여 하면 들 어 오 는 대상 에 대한 수정 을 통 해 내부 변수의 값 을 바 꿀 수 있다.예 를 들 면:
    public final class ImmutableDemo {  
        private final int[] myArray;  
        public ImmutableDemo(int[] array) {  
            this.myArray = array; // wrong  
        }  
    }

    이 방식 은 불변성 을 보장 할 수 없습니다. my Array 와 array 는 같은 메모리 주 소 를 가리 키 고 있 습 니 다. 사용 자 는 ImmutableDemo 외 에 array 대상 의 값 을 수정 하여 my Array 내부 의 값 을 변경 할 수 있 습 니 다.내부 값 이 수정 되 지 않도록 깊이 copy 를 사용 하여 들 어 오 는 값 을 저장 할 수 있 습 니 다.올 바른 방법:
    public final class MyImmutableDemo {  
        private final int[] myArray;  
        public MyImmutableDemo(int[] array) {  
            this.myArray = array.clone();   
        }   
    }

    5. getter 방법 에서 대상 자 체 를 직접 되 돌려 주지 않 고 복제 대상 을 되 돌려 주 는 복사 방법 도 대상 의 유출 을 방지 하고 getter 를 통 해 내부 가 변 멤버 대상 을 얻 은 후에 구성원 변 수 를 직접 조작 하여 구성원 변 수 를 변화 시 키 는 것 을 방지 합 니 다.
    4. String 대상 의 불변성
    string 대상 은 메모리 생 성 후 변경 할 수 없습니다. 변경 할 수 없 는 대상 의 생 성 은 일반적으로 상기 5 가지 원칙 을 만족 시 킵 니 다. String 코드 가 어떻게 실현 되 는 지 봅 시다.
    public final class String
        implements java.io.Serializable, Comparable, CharSequence
    {
        /** The value is used for character storage. */
        private final char value[];
        /** The offset is the first index of the storage that is used. */
        private final int offset;
        /** The count is the number of characters in the String. */
        private final int count;
        /** Cache the hash code for the string */
        private int hash; // Default to 0
        ....
        public String(char value[]) {
             this.value = Arrays.copyOf(value, value.length); // deep copy  
         }
        ...
         public char[] toCharArray() {
         // Cannot use Arrays.copyOf because of class initialization order issues
            char result[] = new char[value.length];
            System.arraycopy(value, 0, result, 0, value.length);
            return result;
        }
        ...
    }

    상기 코드 에서 보 듯 이 다음 과 같은 디자인 디 테 일 을 관찰 할 수 있 습 니 다.
  • String 클래스 는 final 로 수식 되 어 계승 불가
  • string 내부 의 모든 구성원 이 개인 변수 로 설정
  • value 가 존재 하지 않 는 setter
  • value 와 offset 을 final 로 설정 합 니 다.
  • 가 변 배열 value [] 에 들 어 갈 때 copy 를 진행 합 니 다. 내부 변수 에 직접 value [] 를 복사 하 는 것 이 아 닙 니 다.
  • value 를 가 져 올 때 대상 의 인용 을 직접 되 돌려 주 는 것 이 아니 라 대상 의 copy 를 되 돌려 줍 니 다.
  • 이것 은 모두 위 에서 정리 한 변 하지 않 는 유형의 특성 에 부합 되 고 String 유형 이 변 하지 않 는 유형 임 을 보증 합 니 다.
    5. String 대상 의 불가 변성 장단 점
    이전 절 에서 분석 하면 String 데 이 터 는 가 변 류 가 아 닙 니 다. 그러면 이러한 특성 을 설정 하면 어떤 장점 이 있 습 니까?나 는 다음 과 같은 몇 가지 로 요약 한다.
    1. 문자열 상수 탱크 의 필요. 문자열 상수 탱크 는 상수 탱크 에 일부 문자 상 수 를 두 고 반복 적 으로 사용 할 수 있 으 며 매번 같은 대상 을 다시 만 들 거나 저장 공간 을 절약 하지 않도록 합 니 다.그러나 문자열 이 가 변 적 이면 같은 내용 의 String 은 상수 탱크 의 같은 메모리 공간 을 가리 키 며, 어떤 변수 가 이 메모리 의 값 을 바 꾸 었 을 때 다른 옮 겨 다 니 는 값 도 변 경 됩 니 다.그래서 상수 탱크 디자인 의 취지 에 맞지 않 습 니 다.
    2. 라인 안전 고려.같은 문자열 인 스 턴 스 는 여러 스 레 드 에서 공유 할 수 있 습 니 다.이렇게 하면 스 레 드 안전 문제 로 동기 화 를 사용 하지 않 아 도 된다.문자열 자체 가 라인 이 안전 합 니 다.
    3. 클래스 로 더 는 문자열 을 사용 해 야 합 니 다. 정확 한 클래스 를 불 러 올 수 있 도록 보안 을 제공 합 니 다.예 를 들 어 자바. sql. connection 류 를 불 러 오고 싶 은 데 이 값 이 my hacked. Connection 으로 바 뀌 면 데이터 베 이 스 를 알 수 없 는 파 괴 를 초래 할 수 있 습 니 다.
    4. hash 맵 과 캐 시 를 지원 합 니 다.문자열 은 가 변 적 이지 않 기 때문에 만 들 때 hashcode 가 캐 시 되 어 다시 계산 할 필요 가 없습니다.이 때문에 문자열 은 Map 의 키 로 적합 하고 문자열 의 처리 속 도 는 다른 키 대상 보다 빠르다.이것 이 바로 HashMap 의 키 입 니 다. 문자열 을 자주 사용 합 니 다.
    단점:
  • String 대상 값 변경 에 대한 요구 가 있 으 면 대량의 String 대상 을 생 성 합 니 다.
  •  

  • 6. String 대상 의 진짜 불가 변 여부
    String 대상 은 value 를 final 로 설정 하고 여러 메커니즘 을 통 해 구성원 변 수 를 변경 할 수 없 도록 합 니 다.하지만 반사 메커니즘 의 수단 을 통 해 그 값 을 바 꿀 수 있다.예 를 들 면:
        //     "Hello World",      s
        String s = "Hello World"; 
        System.out.println("s = " + s); //Hello World
    
        //  String   value  
        Field valueFieldOfString = String.class.getDeclaredField("value");
        //  value       
        valueFieldOfString.setAccessible(true);
    
        //  s    value    
        char[] value = (char[]) valueFieldOfString.get(s);
        //  value         5   
        value[5] = '_';
        System.out.println("s = " + s);  //Hello_World

    인쇄 결과:
    s = Hello World
    s = Hello_World

    String 의 값 이 변경 되 었 습 니 다.반 사 를 통 해 이른바 '불가 변' 대상 을 수정 할 수 있다 는 것 이다.
    총결산
    가 변 하지 않 는 클래스 는 인 스 턴 스 생 성 후 구성원 이 옮 겨 다 니 는 값 을 바 꿀 수 없습니다.이러한 특성 으로 인해 불 가 변 류 는 스 레 드 안전 기능 을 제공 하지만 대상 이 만 든 비용 도 가 져 왔 습 니 다. 속성 을 변경 할 때마다 새로운 대상 을 다시 만 듭 니 다.JDK 내부 에서 도 Integer, Double, String 등 가 변 적 이지 않 은 종 류 를 많이 제공 했다.String 의 가 변 적 이지 않 은 특성 은 주로 상수 탱크, 스 레 드 안전, 클래스 로드 의 수 요 를 만족 시 키 기 위해 서 입 니 다.불가 변 류 를 합 리 적 으로 사용 하면 매우 큰 이익 을 가 져 올 수 있다.

    좋은 웹페이지 즐겨찾기