Java 字符集 編碼


Java 字符集 編碼

Java默認的字符集是Unicode(占兩個字節byte,一個字節=8比特位bit

詳解:

字符集 編碼

Unicode 是「字符集」;UTF-8 是「編碼規則」(是使用最廣的一種 Unicode 的實現方式)

字符集:為每一個字符分配一個唯一的ID(碼位)

編碼規則:將碼位轉換為字節序列的規則(用什么方式存儲)

 

 

英文/字節

中文/字節

Utf-8(變長)

1

3

Utf-16

2

3-4

GBK

1

2

ISO8859-1

1

1

Unicode

2

2(標點也是)

ASCII

1

2

 

Java的處理方法:

編碼問題存在兩個方面:JVM之內和JVM之外。

  1.編譯器把Java文件編譯后形成class

這里Java文件的編碼可能有多種多樣可以為utf-8(常用),但Java編譯器會自動將這些編碼按照Java文件的編碼格式正確讀取后產生class文件,這里的class文件編碼是Unicode編碼(具體說是UTF-16編碼)。也就是說完成了從UTF-8編碼的文件轉成與平台無關的.class文件了,把UTF-8編碼方式轉成了Unicode。一旦編譯成.class文件,就不用在乎關於我們程序源碼的什么UTF-8編碼了

因此,在Java代碼中定義一個字符串String s="漢字";
不管在編譯前java文件使用何種編碼,在編譯后成class后,他們都是一樣的----Unicode編碼表示。

  2.JVM中的編碼

JVM內部,統一使用Unicode表示,當着字符從JVM內部移動到外部時(即保存為文件系統中的一個文件內容時),就進行了編碼轉換,使用了具體的編碼方案。因此也可以說,所有的編碼轉換只發生在邊界的地方,也就是各種輸入/輸出流的起作用的地方。

JVM加載class文件讀取時候使用Unicode編碼方式正確讀取class文件,那么原來定義的String s="漢字";在內存中的表現形式是Unicode編碼。

 

問題

java中,一個字符等於多少字節?

或者更詳細的問:在java中,一個英文字符等於多少字節?一個中文字符等於多少字節?

 

Java采用unicode來表示字符,java中的一個char2個字節,一個中文或英文字符的unicode編碼都占2個字節,但如果采用其他編碼方式,一個字符占用的字節數則各不相同。

代碼驗證如下:

public static void main(String[] args) {
    String str = "測";
    char x = '測';
    byte[] byteStr = str.getBytes();
    byte[] byteChar = charToByte(x);
    System.out.println("byteStr :" + byteStr.length); // byteStr :3
    System.out.println("byteChar:" + byteChar.length); // byteChar:2
}

// 通過移位獲取char類型的byte數組
public static byte[] charToByte(char c) {
    byte[] b = new byte[2];
    b[0] = (byte) ((c & 0xFF00) >> 8);
    b[1] = (byte) (c & 0xFF);
    return b;
}

 

獲取系統編碼

System.out.println("系統默認編碼:" + System.getProperty("file.encoding")); //查詢結果UTF-8
System.out.println("系統默認字符編碼:" + Charset.defaultCharset()); //查詢結果UTF-8
System.out.println("系統默認語言:" + System.getProperty("user.language")); //查詢結果zh

 

getBytes()方法詳解

另外解釋一下上邊使用的getBytes()方法

在Java,StringgetBytes()方法是得到一個操作系統默認的編碼格式的字節數組。這表示在不同的操作系統下,返回的東西不一樣!

1.str.getBytes();  如果括號中不寫charset,則采用的是Sytem.getProperty("file.encoding"),即當前文件的編碼方式, 

2.str.getBytes("charset");//指定charset,即將底層存儲的Unicode碼解析為charset編碼格式的字節數組方式 

3.String  str=new String(str.getBytes("utf-8"),"gbk")); //將已經解析出來的字節數據轉化為gbk編碼格式的字符串,在內存中即為gbk格式的字節數組轉為Unicode去交互傳遞

 

引申

 問:

"a".getBytes("Unicode").length // 結果為 4

上邊已經說過Unicode一個字符占兩個字節,這里為什么是4字節不是2字節?

為什么Unicode 4個字節

使用for循環遍歷得到的byte數組(還是使用字符 a ):

-2 -1 0 97 

 

發現前邊多了一個 -2 -1 ,這其實是一個字節的BOM標志。

UNICODE 是一種字符集,在 Java 中直接使用 Unicode 轉碼時會按照 UTF-16LE 的方式拆分,由於 UTF-16 分為 UTF-16LE UTF-16BE,也就是小端序和大端序,因此在網絡傳過程中,無法判斷是 LE 還是 BE 序的,因此需要加上一個額外的字節序 BOM 頭。BOM 頭的字符是一個特殊的字符,其 Unicode 編碼為 U+FEFF,字符名為“ZERO WIDTH NON-BREAKING SPACE”,根據 RFC2781 3.2 節規定,開頭兩個字節為 FE FF 的稱為Big-Endian,開頭為 FF FE 的稱為 Little-Endian

 

關於utf-16的解釋:utf-16的方式包含2種字節序,Big Endian字節序和Little Endian字節序
UTF-16 Big EndianFEFF (沒有含義在UCS-2),其中FEFF為標示碼
UTF-16 Little EndianFFFE (沒有含義在UCS-2),java默認選擇Little Endian字節序

 

因此,你直接使用 Unicode 轉換字節的話,也就是按 UTF-16LE 方式進行解碼,會額外地加上 BOM 的兩個字節 FF FE

解決辦法:

可以使用UnicodeBigUnmarked編碼

"a".getBytes("UnicodeBigUnmarked").length // 結果為2

 

參考:

http://bbs.itheima.com/thread-101106-1-1.html

https://blog.csdn.net/lcfeng1982/article/details/6830584 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM