자바 String 가 변성 분석

머리말
이틀 동안 자바 면접 과 관련 된 문 제 를 보고 있 었 는데 우연히 다음 글 을 보 게 되 어 다행 입 니 다.
https://www.jb51.net/article/105448.htm
이 글 의 작 가 는 자바 의 깊이 있 는 학습 에 관 한 일련의 글 을 가지 고 있 는데 볼 만 한 가치 가 있 고 개인 적 으로 매우 좋 고 수확 이 있다 고 생각한다.
원인
问答
우리 가 이해 한 바 와 같이

String hello = "Hello World!";
화해시키다

String xx = new String("Hello World!");
받 은 문자열 의 대상 은 다 릅 니 다.new 방식 은 쌓 인 공간 에서 만 들 어 졌 고 직접적인 문자열 은 상수 탱크 에 먼저 놓 여 있 습 니 다.이와 같은 대상 이 새로 만 들 어 졌 다 면 이 새 대상 에 게 상수 탱크 의 이 주 소 를 직접 참조 하 게 하면 됩 니 다.
이런 장점 은 메모리 공간 을 최대한 절약 할 수 있다 는 것 이다.
new 방식 으로 만 든 것 은 다 릅 니 다.new 로 문자열 을 만 들 면 쌓 인 공간 에서 메모리 하 나 를 열 고 이 메모리 주소 의 인용 을 되 돌려 줍 니 다.따라서 이렇게 만 든 대상 은 내용 이 일치 하 더 라 도 같은 메모리 주 소 를 가리 키 지 않 습 니 다.
다음은 몇 가지 간단 한 코드 로 테스트 를 해 보 겠 습 니 다.

/**
*                       ,       。
*/
equals //                
==  //                 
아래 코드 를 보십시오.

public static void simple() {
  String s1 = "Hello World!";
  String s2 = "Hello World!";
  String s3 = new String("Hello World!");
  String s4 = new String("Hello World!");

  //               
  System.out.println("       :");
  System.out.println(s1==s2);
  System.out.println(s1.equals(s2));

  System.out.println("
new :"); System.out.println(s1==s3); System.out.println(s1.equals(s3)); System.out.println("
new :"); System.out.println(s3==s4); System.out.println(s3.equals(s4)); }
얻 은 결 과 는 다음 과 같다.

       :
true
true

        new  :
false
true

new   :
false
true

결국 우리 가 말 한 것 처럼
딥 소스 코드
예상대로 String 은'가 변 적 이지 않 음'입 니 다.바 텀 을 바 꿀 때마다 마음 에 드 는 문자열 대상 을 만 들 고 새 값 을 부여 합 니 다.
왜 이러 지?우 리 는 소스 코드 에서 진실 을 찾 을 수 있 을 지도 모른다.
字符串源码
아,자바 가 String 류 에 대해 final 형식의 문자 배열 만 유지 하고 있 었 군요.어쩐지 할당 이 안 되 더 라 니.
하지만 의문 이 있 을 지도 모 릅 니 다.어,아니 군요."저 는 문자열 의 내용 을 바 꾸 는 방법 을 자주 사용 합 니 다.""그게 무슨 설명 이 야?"
사실 답 은 여전히 그렇다.그것 은 정말 변 하지 않 았 다.우 리 는 일의 진상 을 보지 못 했다.아래 의 소스 코드 를 보면 알 수 있 을 것 이 라 고 믿는다.

/**
  * Returns a string resulting from replacing all occurrences of
  * {@code oldChar} in this string with {@code newChar}.
  * <p>
  * If the character {@code oldChar} does not occur in the
  * character sequence represented by this {@code String} object,
  * then a reference to this {@code String} object is returned.
  * Otherwise, a {@code String} object is returned that
  * represents a character sequence identical to the character sequence
  * represented by this {@code String} object, except that every
  * occurrence of {@code oldChar} is replaced by an occurrence
  * of {@code newChar}.
  * <p>
  * Examples:
  * <blockquote><pre>
  * "mesquite in your cellar".replace('e', 'o')
  *   returns "mosquito in your collar"
  * "the war of baronets".replace('r', 'y')
  *   returns "the way of bayonets"
  * "sparring with a purple porpoise".replace('p', 't')
  *   returns "starring with a turtle tortoise"
  * "JonL".replace('q', 'x') returns "JonL" (no change)
  * </pre></blockquote>
  *
  * @param oldChar the old character.
  * @param newChar the new character.
  * @return a string derived from this string by replacing every
  *   occurrence of {@code oldChar} with {@code newChar}.
  */
 public String replace(char oldChar, char newChar) {
  if (oldChar != newChar) {
   int len = value.length;
   int i = -1;
   char[] val = value; /* avoid getfield opcode */

   while (++i < len) {
    if (val[i] == oldChar) {
     break;
    }
   }
   if (i < len) {
    char buf[] = new char[len];
    for (int j = 0; j < i; j++) {
     buf[j] = val[j];
    }
    while (i < len) {
     char c = val[i];
     buf[i] = (c == oldChar) ? newChar : c;
     i++;
    }
    return new String(buf, true);
   }
  }
  return this;
 }

소스 코드 에서 명확 하 게 사 용 했 어 요.

new String(buf, true);
호출 자 에 게 새로운 대상 을 되 돌려 주 었 습 니 다.
정말 변 하지 않 나 요?
위의 내용 을 읽 으 면 사실 거의 충분 하 다.하지만 좀 더 깊 은 내용 을 알 아 보 는 것 이 앞으로 프로 그래 밍 에 더 좋 을 것 이 라 고 믿 습 니 다.
원본 코드 에 서 는 char[]value 를 사용 하여 외부 문자열 데 이 터 를 담 습 니 다.즉,문자열 대상 의 가 변 적 이지 않 은 특성 은 value 배열 의 final 특성 에서 비롯 된 것 입 니 다.
그러면 우 리 는 String 의 내용 을 바 꾸 지 않 고 고 개 를 돌려 value 배열 의 내용 을 바 꿀 수 있다 고 생각 할 수 있 습 니 다.(String 대상 의 private 속성 을 반사 적 으로 수정 할 수 있 는 value)결 과 는 어떻게 될 까요?
정 답 은 진짜 변 한다.
아래 코드 부터 볼 수 있어 요.

private static void deep() throws NoSuchFieldException, IllegalAccessException {
  String hello = "Hello World!";
  String xx = new String("Hello World!");
  String yy = "Hello World!";

  /**
   *          ,          
   */
  System.out.println(hello == xx);
  System.out.println(hello == yy);
  System.out.println(xx == yy);

  //   hello, xx, yy       value       
  Field hello_field = hello.getClass().getDeclaredField("value");
  hello_field.setAccessible(true);
  char[] hello_value = (char[]) hello_field.get(hello);
  System.out.println( hello_field.get(hello));

  Field xx_field = xx.getClass().getDeclaredField("value");
  xx_field.setAccessible(true);
  char[] xx_value = (char[]) xx_field.get(xx);
  System.out.println(xx_field.get(xx));

  Field yy_field = yy.getClass().getDeclaredField("value");
  yy_field.setAccessible(true);
  char[] yy_value = (char[]) yy_field.get(yy);
  System.out.println(yy_field.get(yy));
  /**
   *                         value,             ,java                     
   * 
   */

  //             value  
  Field field = hello.getClass().getDeclaredField("value");
  field.setAccessible(true);
  char[] value = (char[]) field.get(hello);
  System.out.println(value);
  value[5] = '^';
  System.out.println(value);

  //   xx     
  System.out.println(xx);
 }

결 과 는?

false
true
false
[C@6d06d69c
[C@6d06d69c
[C@6d06d69c
Hello World!
Hello^World!
Hello^World!
정말 바 뀌 었 어.
그리고 우 리 는 hello,xx,yy 가 최종 적 으로 메모리 에 있 는 같은 value 문자 배열 을 가리 키 는 것 을 발견 할 수 있 습 니 다.이것 은 자바 가 밑바닥 에서 충분 한 최적화 처 리 를 했다 는 것 을 설명 한다.
문자열 대상 을 만 들 때 바 텀 은 해당 내용 을 담 은 문자 배열 에 대응 합 니 다.이 때 같은 문자열 이 또 오 면 value 배열 에 대해 방금 인용 한 것 을 직접 가 져 오 면 됩 니 다.(자바 에서 배열 도 대상 형식의 데이터 라 는 것 을 잘 알 고 있 습 니 다.이해 하기 어렵 지 않 습 니 다)
문자열 의 직접 인용 방식 이 든 new 의 새로운 문자열 의 방식 이 든 결 과 는 같 습 니 다.내부 의 문자 배열 은 메모리 의 같은'대상'(value 문자 배열)을 가리 키 고 있 습 니 다.
총결산
조금 어 지 럽 지만 이 점 에서 스 트 링 의 불가 변성 은 여전히 외부 에 있다 는 것 을 알 수 있다.밑바닥 에서 자 바 는 이 모든 것 을 투명 하 게 했다.우 리 는 String 대상 이 이런 특성 을 가지 고 있다 는 것 만 알 면 된다.
다른 데 일리 애플 리 케 이 션 은 String 대상 에 따라 가 변 적 으로 사용 하면 됩 니 다.
읽 어 주 셔 서 감사합니다. 여러분 에 게 도움 이 되 기 를 바 랍 니 다.본 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기