2013-07-28 37 views
25

Nếu tôi chuyển đổi một ký tự thành byte và sau đó quay lại char, nhân vật đó biến mất một cách bí ẩn và trở thành cái gì đó khác. Sao có thể như thế được?Byte và chuyển đổi char trong Java

Đây là mã:

char a = 'È';  // line 1  
byte b = (byte)a; // line 2  
char c = (char)b; // line 3 
System.out.println((char)c + " " + (int)c); 

Cho đến dòng 2 mọi thứ đều tốt:

  • Trong dòng 1 tôi có thể in "a" trong giao diện điều khiển và nó sẽ hiển thị "e".

  • Trong dòng 2 tôi có thể in "b" trong bảng điều khiển và nó sẽ hiển thị -56, nghĩa là 200 vì byte được ký. Và 200 là "È". Vì vậy, nó vẫn ổn.

Nhưng có gì sai trong dòng 3? "c" trở thành cái gì khác và chương trình in ? 65480. Đó là một cái gì đó hoàn toàn khác.

Tôi nên viết gì ở dòng 3 để có được kết quả chính xác?

+4

Một 'byte' là' 8 bit'.'char' là' 16 bit'. Có ý tưởng? –

+0

char mất 2byte. – Ankit

+0

@RohitJain Và một ký tự - theo đó tôi có nghĩa là một điểm mã Unicode - có thể lấy hai ký tự hoặc bốn byte. Hơn nữa, ai biết những gì bình thường hóa hình thành những thứ đang ở? Chuỗi '" È "' có thể tự bao gồm một hoặc hai điểm mã tùy thuộc vào việc nó có ở dạng chuẩn hóa C hay D tương ứng hay không. – tchrist

Trả lời

44

Một ký tự trong Java là đơn vị mã Unicode được coi là số không dấu. Vì vậy, nếu bạn thực hiện c = (char)b giá trị mà bạn nhận được là 2^16 - 56 hoặc 65536 - 56.

Hay chính xác hơn, các byte là lần đầu tiên chuyển đổi sang một số nguyên ký kết với giá trị sử dụng 0xFFFFFFC8dấu hiệu mở rộng trong một chuyển đổi mở rộng . Điều này lần lượt sau đó được thu hẹp xuống 0xFFC8 khi truyền tới số char, chuyển thành số dương 65480.

Từ đặc tả ngôn ngữ:

5.1.4. Widening and Narrowing Primitive Conversion

Thứ nhất, byte được chuyển đổi sang một int qua mở rộng chuyển đổi nguyên thủy (§5.1.2), và sau đó là int kết quả được chuyển đổi sang một char bằng cách thu hẹp chuyển đổi nguyên thủy (§5.1.3).


Để có được điểm sử dụng đúng char c = (char) (b & 0xFF) lần đầu tiên chuyển đổi giá trị byte của b đến số nguyên dương 200 bằng cách sử dụng một mặt nạ, zeroing 24 bit đầu sau khi chuyển đổi: 0xFFFFFFC8 trở thành 0x000000C8 hoặc số dương 200 trong số thập phân.


Trên đây là một lời giải thích trực tiếp về những gì xảy ra trong quá trình chuyển đổi giữa byte, intchar loại nguyên thủy.

Nếu bạn muốn mã hóa/giải mã ký tự từ byte, sử dụng Charset, CharsetEncoder, CharsetDecoder hoặc một trong các phương pháp tiện lợi như new String(byte[] bytes, Charset charset) hoặc String#toBytes(Charset charset). Bạn có thể lấy bộ ký tự (chẳng hạn như UTF-8 hoặc Windows-1252) từ StandardCharsets.

+3

Thực ra, một Java 'char' không phải là mã Unicode * **. Nó là đơn vị mã UTF-16 * **. Để thực sự đại diện cho một "ký tự" tùy ý (nghĩa là một điểm mã thực), một Java 'char' không đủ tốt: bạn phải sử dụng' int' (có hiệu quả cho bạn UTF-32), có thể mất đến hai ký tự trong ký hiệu UTF-16 cũ. Đó là lý do tại sao mọi thứ đều có API 'codePointAt', không chỉ là API cũ charAt' cũ. – tchrist

+1

@tchrist yeah, điều này đã thay đổi một chút khi Unicode đi qua biên giới 64Ki. –

+0

Tại sao 'char c = (char) (b & 0xFF)' chỉ sử dụng một byte đơn, khi các ký tự Java được cho là hai byte? – statueofmike

Các vấn đề liên quan