StringLatin1是什么?
从JDK9开始,String对象不再以char[]形式存储,而是以名为value的byte[]形式存储。value有一个名为coder的编码标记,该标记有两种取值:LATIN1和UTF-16(UTF-16使用大端法还是小端法取决于系统)。Java中存储String的byte数组的默认编码是LATIN1(即ISO-8859-1)和UTF16。
因此,JDK9就将String分为两套编码格式,由JVM识别系统的编码,而后选择调用的编码。
ISO8859-1(Latin-1)
ISO8859-1,通常叫做Latin-1。Latin-1包括了书写所有西方欧洲语言不可缺少的附加字符。
ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。
ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。欧元符号出现的比较晚,没有被收录在ISO-8859-1当中。
因为ISO-8859-1编码范围使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃。换言之,把其他任何编码的字节流当作ISO-8859-1编码看待都没有问题。这是个很重要的特性,MySQL数据库默认编码是Latin1就是利用了这个特性。ASCII编码是一个7位的容器,ISO-8859-1编码是一个8位的容器。
ISO-8859-1 的较低部分(从 1 到 127 之间的代码)是最初的 7 比特 ASCII。
ISO-8859-1 的较高部分(从 160 到 255 之间的代码)全都有实体名称。
基础方法
// 返回Latin1-String的字节值value中包含的char的个数public static int length(byte[] value) {return value.length;}// true:表示当前序列在Latin1编码范围内,ISO-8859-1编码是一个8位的容器public static boolean canEncode(int cp) {return cp >>> 8 == 0;}// 用val在[index, index+len)范围内的byte值创建Stringpublic static String newString(byte[] val, int index, int len) {return new String(Arrays.copyOfRange(val, index, index + len), LATIN1);}// 将val[fromIndex, toIndex)的内存单元清零public static void fillNull(byte[] val, int index, int end) {Arrays.fill(val, index, end, (byte) 0);}// 哈希码public static int hashCode(byte[] value) {int h = 0;for (byte v : value) {// s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]。h = 31 * h + (v & 0xff);}return h;}
1 获取char/char[]
下面的方法主要进行byte数组转换为char或char数组。
// 将LATIN1-String内部的字节转换为char后返回public static char getChar(byte[] val, int index) {return (char) (val[index] & 0xff);}// 将LATIN1-String内部的字节转换为char后返回,加入范围检查public static char charAt(byte[] value, int index) {if (index < 0 || index >= value.length) {throw new StringIndexOutOfBoundsException(index);}return (char) (value[index] & 0xff);}// 将LATIN1-String内部的字节批量转换为char后存入char数组public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) {inflate(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);}// 将LATIN1-String内部的字节批量转换为char后存入char数组@HotSpotIntrinsicCandidatepublic static void inflate(byte[] src, int srcOff, char[] dst, int dstOff, int len) {for (int i = 0; i < len; i++) {dst[dstOff++] = (char) (src[srcOff++] & 0xff);}}// 将LATIN1-String内部的字节全部转换为char后返回public static char[] toChars(byte[] value) {char[] dst = new char[value.length];// 将LATIN1-String内部的字节批量转换为char后存入dstinflate(value, 0, dst, 0, value.length);return dst;}
2 获取byte/byte[]
// 将c的一个低字节转换为LATIN-String内部的字节,存入valpublic static void putChar(byte[] val, int index, int c) {//assert (canEncode(c));val[index] = (byte) (c);}// 将char转换为LATIN1-String内部的字节,并返回public static byte[] toBytes(char c) {return new byte[]{(byte) c};}// 将val[off, off+len)中的一组Unicode值批量转换为LATIN1-String内部的字节,再返回public static byte[] toBytes(int[] val, int off, int len) {byte[] ret = new byte[len];for (int i = 0; i < len; i++) {int cp = val[off++];// 如果当前序列不在Latin1编码范围内,转码失败if (!canEncode(cp)) {return null;}ret[i] = (byte) cp;}return ret;}// 从LATIN1-String内部的字节转为UTF16-String内部的字节@HotSpotIntrinsicCandidatepublic static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {StringUTF16.inflate(src, srcOff, dst, dstOff, len);}// 从LATIN1-String内部的字节转为UTF16-String内部的字节后返回public static byte[] inflate(byte[] value, int off, int len) {// 创建长度为2*len的字节数组byte[] ret = StringUTF16.newBytesFor(len);// 从LATIN-String内部的字节转为UTF16-String内部的字节inflate(value, off, ret, 0, len);return ret;}// 将LATIN1-String内部的字节转换为LATIN1-String内部的字节,由于都是单字节,直接用了复制public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) {System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);}
