자바 string 의 세부 분석

6865 단어 자바string
우선 자바 의 String 을 말 합 니 다.C/C++로 전환 하기 로 결 정 했 지만 오늘 문제 가 생 겼 으 니 한번 보 겠 습 니 다.String 의 정 의 는 다음 과 같 습 니 다
 
public final class String
{
private final char value[]; //
private final int offset; //
private final int count; //
private int hash; // hash
......
}
Debug 에서 저 장 된 값 을 볼 수 있 습 니 다 설명 이 필요 한 것 은 hashCode()를 호출 한 적 이 없다 면 hash 의 값 은 0 입 니 다.이 곳 의 value,즉 실제 저 장 된 문자열 의 값(즉'문자열 테스트')을 쉽게 알 수 있 는 char 배열 입 니 다.각 char 의 값 은 얼마 입 니까?쉽게 검증:유 니 코드.여기까지 만 해도 우리 가 자주 사용 하 는 subString 이 어떻게 이 루어 졌 는 지 알 수 있 습 니 다.우리 가 이 루어 졌 다 면 new String 은 같은 value(char 배열)를 사용 하고 offset 과 count 만 수정 하면 됩 니 다.이렇게 하면 공간 도 절약 할 수 있 고(복사 할 필요 가 없 음)빠 르 며,사실상 도 마찬가지 입 니 다
 
public String substring(int beginIndex) {
return substring(beginIndex, count);
}
public String substring(int beginIndex, int endIndex) {
......
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
}
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
문자열 을 토론 하 는 이상 JVM 은 기본적으로 어떤 인 코딩 을 사용 합 니까?디 버 깅 을 통 해 알 수 있 듯 이:
 
public static Charset defaultCharset() {
if (defaultCharset == null) {
synchronized (Charset.class) {
java.security.PrivilegedAction pa = new GetPropertyAction("file.encoding");
String csn = (String)AccessController.doPrivileged(pa);
Charset cs = lookup(csn);
if (cs != null)
defaultCharset = cs;
else
defaultCharset = forName("UTF-8");
}
}
그 중에서 defaultCharset 의 값 은:-dfile.encoding=utf-8 을 통 해 설정 할 수 있 습 니 다.물론'abc'로 설정 하고 싶 으 면 가능 하지만 기본적으로 UTF-8 로 설정 합 니 다.System.getProperty(file.encoding)를 통 해 구체 적 인 값 을 볼 수 있 습 니 다.default Charset 를 보면 왜 일 까요?네트워크 전송 과정 에서 모두 byte 배열 이 어야 하기 때문에 서로 다른 인 코딩 방식 으로 얻 은 byte 배열 은 다 를 수 있 습 니 다.그래서 인 코딩 방식 을 어떻게 얻 었 는 지 알 아야 되 는 거 죠?구체 적 으로 byte 배열 을 얻 는 방법 은 바로 우리 가 아래 에서 중점적으로 볼 getBytes 입 니 다.마지막 으로 호출 할 것 은 CharsetEncoder 의 encode 방법 입 니 다.다음 과 같 습 니 다
 
public final CoderResult encode(CharBuffer in, ByteBuffer out, boolean endOfInput) {
int newState = endOfInput ? ST_END : ST_CODING;
if ((state != ST_RESET) && (state != ST_CODING) && !(endOfInput && (state == ST_END)))
throwIllegalStateException(state, newState);
state = newState;
for (;;) {
CoderResult cr;
try {
cr = encodeLoop(in, out);
} catch (BufferUnderflowException x) {
throw new CoderMalfunctionError(x);
} catch (BufferOverflowException x) {
throw new CoderMalfunctionError(x);
}
if (cr.isOverflow())
return cr;
if (cr.isUnderflow()) {
if (endOfInput && in.hasRemaining()) {
cr = CoderResult.malformedForLength(in.remaining());
} else {
return cr;
}
}
CodingErrorAction action = null;
if (cr.isMalformed())
action = malformedInputAction;
else if (cr.isUnmappable())
action = unmappableCharacterAction;
else
assert false : cr.toString();
if (action == CodingErrorAction.REPORT)
return cr;
if (action == CodingErrorAction.REPLACE) {
if (out.remaining() < replacement.length)
return CoderResult.OVERFLOW;
out.put(replacement);
}
if ((action == CodingErrorAction.IGNORE) || (action == CodingErrorAction.REPLACE)) {
in.position(in.position() + cr.length());
continue;
}
assert false;
}
}
물론 필요 한 인 코딩 형식 에 따라 대응 하 는 CharsetEncoder 를 선택 합 니 다.가장 중요 한 것 은 서로 다른 CharsetEncoder 가 서로 다른 encodeLoop 방법 을 실현 합 니 다.여기 왜 여기 for(;)가 있 는 지 모 르 겠 지만?사실 CharsetEncoder 가 있 는 가방(nio)과 그 매개 변 수 를 보면 대충 알 수 있 습 니 다.이 함 수 는 흐름 을 처리 할 수 있 습 니 다.(우리 가 여기 서 사용 할 때 순환 하지 않 지만)encodeLoop 방법 에 서 는 가능 한 한 많은 char 를 byte 로 변환 합 니 다.new String 의 차이 가 많 지 않 은 것 이 위의 역 과정 입 니 다.실제 개발 과정 에서 오류 가 자주 발생 합 니 다.파일 을 업로드 할 때 파일 이름 을 가 져 옵 니 다.JS 가 백 엔 드 로 전 달 된 문자열;먼저 다음 코드 의 실행 결 과 를 시도 해 보 세 요
 
public static void main(String[] args) throws Exception {
String str = " ";
// -41 -42 -73 -5 -76 -82
printArray(str.getBytes());
// -27 -83 -105 -25 -84 -90 -28 -72 -78
printArray(str.getBytes("utf-8"));
// ???
System.out.println(new String(str.getBytes(), "utf-8"));
// ?
System.out.println(new String(str.getBytes("utf-8"), "gbk"));
// ??
System.out.println(new String(" ?".getBytes("gbk"), "utf-8"));
// -41 -42 -73 -5 63 63
printArray(new String(" ?".getBytes("gbk"), "utf-8").getBytes());
}
public static void printArray(byte[] bs){
for(int i = 0; i < bs.length; i++){
System.out.print(bs[i] + " ");
}
System.out.println();
}
프로그램의 설명 에서 출력 결 과 를 설명 합 니 다.GBK 에서 2 개의 byte 는 한 자 를 표시 하기 때문에 6 개의 byte 가 있 습 니 다.UTF-8 에서 3 개의 byte 가 한 자 를 표시 하기 때문에 9 개의 byte 가 생 겼 다.GBK 로 생 성 할 수 없 는 byte 배열 을 통 해 UTF-8 규칙 에 따라 문자열 을 생 성하 기 때문에??;이것 은 자주 어 지 러 운 코드 를 만 나 는 이유 입 니 다.GBK 는 UTF-8 로 생 성 된 byte 를 사용 하여 문자열 을 생 성 할 수 있 습 니 다.위 에 난 코드 가 생 성 되 었 지만 컴퓨터 는 그렇게 생각 하지 않 기 때문에 getBytes 를 통 해 바이트 배열 을 얻 을 수 있 습 니 다.이 배열 은 utf-8 로 식별 할 수 있 습 니 다.마지막 두 개 63(?)encode 가 채 워 야 합 니 다(또는 바이트 가 직접 채 워 지지 않 았 거나 이 곳 은 자세히 보지 않 았 습 니 다).GBK 와 UTF-8 은 자모 와 숫자의 인 코딩 이 같 기 때문에 이 몇 가지 문자 의 처리 에 있어 서 난호 가 발생 하지 않 습 니 다.그러나 그들 이 한자 에 대한 인 코딩 은 확실히 다 릅 니 다.이것 이 바로 많은 문제 의 기원 입 니 다.아래 코드 를 보 세 요.new String("우리".getBytes("UTF-8"),"GBK").getBytes("GBK"),"UTF-8").분명히 이 코드 의 결 과 는'우리'이지 만 우리 에 게 무슨 소 용이 있 습 니까?우선 우 리 는 new String("우리".getBytes("UTF-8"),"GBK")에 주의 합 니 다.이 코드 의 결 과 는 난 장 판 이 었 고 많은 난 장 판 은'이렇게 난 장 판'이 었 다.그러나 기억 해 야 한다.이곳 의 난 은 우리 에 게 있어 컴퓨터 에 있어 서'난'과'난'이 라 고 할 수 없다.그것 은 우리 가 거의 포기 할 때 난 코드 에서'getBytes(GBK)'를 통 해'중심 골'을 얻 을 수 있다.그리고 우 리 는'중심 골'로 원래 의 문자열 을 복원 할 수 있다.위의 이 코드 는'GBK'와'UTF-8'간 의 난 코드 문 제 를 해결 할 수 있 을 것 같 지만 이런 해결 방법 도 특수 한 상황 에 국한 된다.모든 연속 한자 의 개 수 는 짝수 이다!원인 은 위 에서 이미 말 했 으 니,여 기 는 군말 하지 않 겠 다.그럼 이 문 제 는 어떻게 해결 합 니까?첫 번 째 해결 방법:엔 코드 URI 는 왜 이런 방법 을 사용 합 니까?이 유 는 간단 하 다.GBK 와 UTF-8 은%,숫자,알파벳 에 대한 인 코딩 이 통일 되 어 있 기 때문에 encode 를 전송 한 후의 문자열 은 100%이 두 가지 인 코딩 에서 같은 것 을 얻 은 다음 에 decode 에서 문자열 을 얻 으 면 된다.String 의 형식 에 따 르 면 encode 와 decode 의 효율 이 매우 높다 고 추측 할 수 있 기 때문에 이것 도 좋 은 해결 방법 이 라 고 할 수 있다.두 번 째 해결 방법:인 코딩 형식 을 통일 하 는 데 는 웹 x 광산 건설 을 사용 합 니 다.웹 x.xml 에 default Charset="UTF-8"을 설정 하면 됩 니 다.

좋은 웹페이지 즐겨찾기