2012-10-04 4 views
3

Java String (byte []) 생성자 (Java 6)의 의미를 이해하는 데 어려움을 겪고 있습니다. 결과 String 객체의 길이는 대개 틀립니다. 아마도 여기 누군가가 왜 이것이 의미가 있는지 설명 할 수 있습니다.바이트 배열로 구성된 Java 문자열의 길이가 잘못되었습니다.

import java.nio.charset.Charset; 

public class Test { 
    public static void main(String[] args) { 
     String abc1 = new String("abc"); 
     byte[] bytes = new byte[32]; 

     bytes[0] = 0x61; // 'a' 
     bytes[1] = 0x62; // 'b' 
     bytes[2] = 0x63; // 'c' 
     bytes[3] = 0x00; // NUL 

     String abc2 = new String(bytes, Charset.forName("US-ASCII")); 

     System.out.println("abc1: \"" + abc1 + "\" length: " + abc1.length()); 
     System.out.println("abc2: \"" + abc2 + "\" length: " + abc2.length()); 

     System.out.println("\"" + abc1 + "\" " + 
       (abc1.equals(abc2) ? "==" : "!=") + " \"" + abc2 + "\""); 
    } 
} 

이 프로그램의 출력은 다음과 같습니다 :

abc1: "abc" length: 3 
abc2: "abc" length: 32 
"abc" != "abc" 

문자열 바이트에 대한 문서는 [] 생성자 상태 "새로운 문자열의 길이

는 다음과 같은 작은 자바 프로그램을 고려 charset의 함수이며 따라서 바이트 배열의 길이와 같지 않을 수 있습니다. " 정말로 사실이며 US-ASCII 문자 세트에서 문자열 "abc"의 길이는 32가 아니라 3입니다.

이상하게도 abc2에 공백 문자가 없더라도 abc2.trim()은 동일한 문자를 반환합니다 문자열이지만 길이가 3의 올바른 값으로 조정되고 abc1.equals (abc2)가 true를 반환하는 경우 ... 명백한 내용이 누락 되었습니까?

예, 생성자에 명시적인 길이로 전달할 수 있음을 알고 있습니다. 기본 의미를 이해하려고합니다.

+0

'bytes [3] '대신'bytes [2]'를 사용하셨습니까? –

답변

13

Java에서 문자열은 널로 구분되지 않습니다. 바이트 배열에서 생성 된 문자열은 배열의 전체 길이를 사용합니다. 0x00은 문자 '\0'으로 일대일 변환하므로 결과 문자열의 전체 배열은 — 32입니다. System.out에 인쇄하면 null 문자의 너비가 0이므로 "abc"처럼 보이지만 정말 "abc \ 0 \ 0 \ 0 ..."(32 문자)입니다.

이유는 trim()'\0'이 공백으로 간주하기 때문입니다.

문자열의 널로 구분 된 바이트 표현을 String으로 변환하려면 중지 할 색인을 찾아야합니다. 그런 다음 (@Brian 주석에서 언급 한 것처럼) 다른 String 생성자를 사용할 수 있습니다.

String abc2 = new String(bytes, 0, indexOfFirstNull, Charset.forName("US-ASCII")); 

그러나이 작업은주의해서 수행해야합니다. 플랫폼에 US-ASCII 문자 세트를 사용하고 있습니다. 여기서 첫 번째 0 바이트의 인덱스는 자연스럽게 멈추는 위치입니다. 그러나 많은 문자 집합 (예 : UTF-16)에서 0 바이트는 실제 텍스트의 정상적인 부분으로 발생할 수 있습니다.

+1

+1 자바 문자열이 C 문자열이 아니라는 것을 명확히하기 위해 +1 : 아마도 문자열 (byte [], int, int, String) 생성자를 언급 할 가치가 있습니다. 끈. – Brian

5

결과 문자열 개체의 길이가 보통 잘못되었습니다.

아니요, 그렇습니다. 그게 무슨 뜻인지 오해 한 것입니다. 기본적으로 바이트 당 한 문자를 기준으로 문자열을 만듭니다. US-ASCII 인코딩을 사용하는 경우입니다. abc2 더 공백 문자를 포함하지 비록

이상하게

는 abc2.trim는() 같은 문자열을 반환하지만 3 abc1.equals의 올바른 값으로 조정 길이 (abc2) ... 오전 true를 반환 나는 명백한 무엇인가 놓치고있다?

trim() 상태 용 문서 (두 조건 후 이는 적용되지 않는다)

  • 를 들어, k 문자열의 첫 번째 문자의 인덱스하자 \ u0020 '라고하고, m이 코드에서'\ u0020 '보다 큰 문자열의 마지막 문자 색인이되도록하십시오. 인덱스 k의 문자로 시작되어 인덱스 m의 문자로 끝나는이 문자열의 부분 문자열을 나타내는 새로운 String 객체가 만들어집니다. 즉 this.substring (k, m + 1)의 결과입니다.

그래서 trim() 기본적으로 "포괄적 인 U + 0020로 + 0000 U"동등하게 "공백"을 취급합니다. 그것은 "공백"을 기괴하게 부정확하게 (읽기 : 전 (前) 유니 코드) 표현하지만 동작을 설명합니다.

은 기본적으로 당신이보고있는 것은 :

바이트 배열에서 문자열을 구성하고 무관
String trailingNulls = "abc\0\0\0\0\0\0"; 
String trimmed = trailingNulls.trim(); 
System.out.println(trimmed.length()); // 3 

.

+0

흥미롭게도,'Character.isWhitespace ('\ 0')'는'false'를 반환합니다. –

+0

실제로 해명 해줘서 고마워. – user1720325

+0

@TedHopp : 물론입니다. 공백에 대한 이상한 정의이지만 문서화 된대로 동작합니다. –

0

- 자바의 Object 타입되는 모든 문자열의 먼저, 동일() Object 클래스의 방법을 비교하는 ..

예 :

"abc" .equals("abc")

-trim() 메서드를 사용하여 결과 문자열에서 \0을 제거하면 원하는 결과를 얻을 수 있습니다.

0

우선 할당 된 모든 인덱스가 잘못되었습니다. 당신이 이유를 알게됩니다 String 클래스의 equals 방법을 선택하면 그들은

 bytes[0] = 0x61; // 'a' 
     bytes[1] = 0x62; // 'b' 
     bytes[2] = 0x63; // 'c' 
     bytes[3] = 0x00; // NUL 

을해야합니다. char[]을 반복하고 인덱스가 있으면 각 값을 확인합니다. 길이가 char[]의 다른 경우 그것은 당신에게 돌아갑니다 그래서 false.

while (n-- != 0) { 
       if (v1[i++] != v2[j++]) 
        return false; 
      } 

수정은 k는의 인덱스하자, 그렇지 않으면 trim

abc2.equals(abc1.trim()) 

자바 문서 String#trim()

으로 사용하는 것입니다 코드가 '\ u0020'보다 큰 캐릭터 라인의 최초의 캐릭터. m를, 코드가 '\ u0020'보다 큰 캐릭터 라인의 마지막 캐릭터의 인덱스로한다.

+0

예, 바이트 배열 색인 문제는 제 게시물에 오타였습니다. 사과드립니다. – user1720325

관련 문제