java utf-8编码字节在奇数字符的字符串中的变化

java utf-8编码字节在奇数字符的字符串中的变化,java,encoding,utf-8,Java,Encoding,Utf 8,我有以下代码: public static void main(String args[]) throws UnsupportedEncodingException { System.setProperty("file.encoding", "gbk"); String name = "こんにちわ"; String copy = new String(name.getBytes("utf-8")); byte[] b1 = name.getBytes("utf

我有以下代码:

public static void main(String args[]) throws UnsupportedEncodingException {
    System.setProperty("file.encoding", "gbk");

    String name = "こんにちわ";
    String copy = new String(name.getBytes("utf-8"));

    byte[] b1 = name.getBytes("utf-8");
    byte[] b2 = copy.getBytes();

    System.out.println("b1: " + Arrays.toString(b1));
    System.out.println("b2: " + Arrays.toString(b2));
}
控制台输出为:

b1:[-29,-127,-109,-29,-126,-109,-29,-127,-85,-29,-127,-95,-29,-126,-113]
b2:[-29,-127,-109,-29,-126,-109,-29,-127,-85,-29,-127,-95,-29,-126,63]

注意,新字符串中的最后一个字节不同


现在,如果我使用输入
String name=”こんにち";(仅4个日文字符)改为:

b1:[-29,-127,-109,-29,-126,-109,-29,-127,-85,-29,-127,-95]
b2:[-29,-127,-109,-29,-126,-109,-29,-127,-85,-29,-127,-95]

这次字节完全相同


我在windows上使用java jdk1.6.045。默认字符集为
gbk

我是否遇到了一些编码限制?

基本上,程序的前四行相当于:

    String name = "こんにちわ";
    byte[] b1 = name.getBytes("utf-8");

    String a = new String( name.getBytes("utf-8"), "gbk" );
    byte[] b2 = a.getBytes("gbk");
也就是说,您正在获取一个字节数组(
b1
),它是日语字符串的UTF-8表示形式,并告诉Java“这个字节数组采用GBK编码,请将其转换为文本”

这将不起作用,如果您打印
字符串,您将看到它不会打印日语文本,而是一些中文乱码-加上替换字符(“�)结尾

在内部,Java字符串是用UTF-16编码的。但是当您转换成字节数组或从字节数组转换成字节数组时,您必须指定编码。编码彼此不同,可能使用相同的字节值或字节值序列来表示完全不同的字符

在本例中,UTF-8中的字节序列在GBK中是不合法的,因此,Java正在用替换字符替换它们

如果您想从
b1
创建一个新字符串,并且它仍然是
こんにちわ
,您需要创建一个
a
告诉Java字节是UTF-8格式的

    String a = new String( name.getBytes("utf-8"), "utf-8" );
然后,您的
a
将等于
name

然后,如果您只执行
a.getBytes()
,您将在GBK中获得表示该字符串的字节。它将不同于
b1
,因为它采用不同的编码。要获得相同的数组,您需要使用相同的编码(
a.getBytes(“utf-8”)

  • 尽量不要依赖Java的默认字符集。从字符串中获取字节以及将字节转换为字符串时,请始终指定准确的字符集
  • 不同的字符集为同一字符串生成不同的字节数组
  • 不带字符集参数的
    getBytes()
    String(byte[])
    不会给出
    字符串下的实际字节序列。它们使用JVM的默认字符集—在您的情况下是GBK

基本上,程序的前四行相当于:

    String name = "こんにちわ";
    byte[] b1 = name.getBytes("utf-8");

    String a = new String( name.getBytes("utf-8"), "gbk" );
    byte[] b2 = a.getBytes("gbk");
也就是说,您正在获取一个字节数组(
b1
),它是日语字符串的UTF-8表示形式,并告诉Java“这个字节数组采用GBK编码,请将其转换为文本”

这将不起作用,如果您打印
字符串,您将看到它不会打印日语文本,而是一些中文乱码-加上替换字符(“�)结尾

在内部,Java字符串是用UTF-16编码的。但是当您转换成字节数组或从字节数组转换成字节数组时,您必须指定编码。编码彼此不同,可能使用相同的字节值或字节值序列来表示完全不同的字符

在本例中,UTF-8中的字节序列在GBK中是不合法的,因此,Java正在用替换字符替换它们

如果您想从
b1
创建一个新字符串,并且它仍然是
こんにちわ
,您需要创建一个
a
告诉Java字节是UTF-8格式的

    String a = new String( name.getBytes("utf-8"), "utf-8" );
然后,您的
a
将等于
name

然后,如果您只执行
a.getBytes()
,您将在GBK中获得表示该字符串的字节。它将不同于
b1
,因为它采用不同的编码。要获得相同的数组,您需要使用相同的编码(
a.getBytes(“utf-8”)

  • 尽量不要依赖Java的默认字符集。从字符串中获取字节以及将字节转换为字符串时,请始终指定准确的字符集
  • 不同的字符集为同一字符串生成不同的字节数组
  • 不带字符集参数的
    getBytes()
    String(byte[])
    不会给出
    字符串下的实际字节序列。它们使用JVM的默认字符集—在您的情况下是GBK

您面临一个常见问题,您使用的是默认平台编码,其字节序列编码不同。 这条线

byte[] b1 = name.getBytes("utf-8");
使用utf-8编码将字符串转换为字节[]。 这一行:

String a = new String( name.getBytes("utf-8"));
从字节数组创建字符串,但不指定字符集。这可能是一个问题,因为jvm“获取自己的值”;请注意,string类还具有以下构造函数:

String(byte[] bytes, Charset charset)
它允许您指定如何使用作为第二个参数传递的编码从字节序列创建字符串

stringa=newstring(name.getBytes(“utf-8”);
正在使用默认的格式,从您的注释中读取,该格式是
gbk
。 所以你真正要做的是:

String a = new String( name.getBytes("utf-8"),"gbk");
而不是

String a = new String( name.getBytes("utf-8"),"UTF-8");
棘手的部分是一些编码重叠,即它们转换了一些(但不是全部)具有相同字节序列的符号;因此它们以某种方式表示某些字符串,但以另一种方式表示另一些字符串。例如,ISO8859-1以与ISO8859-15相同的方式表示字符,但欧元和其他一些字符除外