자바 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 대상 에 따라 가 변 적 으로 사용 하면 됩 니 다.
읽 어 주 셔 서 감사합니다. 여러분 에 게 도움 이 되 기 를 바 랍 니 다.본 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.