关于JAVA中String 编码的问题

skyhits1921 2009-04-15 09:53:36
关于编码问题,请各位达人能提出深刻的见解,不要去百度搜一下,摘抄一些人云亦云的东西。
代码如下,对产生的结果进行分析

String str = "中国";
System.out.println("第一部分-------------------------------------------");
System.out.println(str.length());
System.out.println(str.getBytes().length);
System.out.println(new String(str.getBytes(),"UTF-8").length());
System.out.println(new String(str.getBytes(),"UTF-8").getBytes().length);
System.out.println("--------------------------------------------------");

String str2 ="abc中国";
System.out.println("第二部分-------------------------------------------");
System.out.println(str2.length());
System.out.println(str2.getBytes().length);
System.out.println(new String(str2.getBytes(),"UTF-8").length());
System.out.println(new String(str2.getBytes(),"UTF-8").getBytes().length);
System.out.println("--------------------------------------------------");

如果觉得不够分,我可以再加。
...全文
6512 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
hbgzg3006 2009-04-20
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 skyhits1921 的回复:]
引用 8 楼 hbgzg3006 的回复:

Java code
            String str = "中国";
            System.out.println(str.length());  //这些应该都没有问题,关键在下面
            System.out.println(str.getBytes().length);//注意这里是得到的gbk的字节,一个汉字gbk编码是2个字节
            System.out.println(new String(str.getBytes(),"UTF-8"));
            //这里用得到的gbk的字节去转换成utf-8,需要注意的是一般…
[/Quote]
你可以看一下eclipse-〉window->preferences->general->workplace 里面有eclipse默认的编码是什么(gbk)。另外一个环境就是windows下用txt了,你可以搜一下默认是gb2312,其实gbk是比包括gb2312,但更大的一个字符集。
skyhits1921 2009-04-19
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 hbgzg3006 的回复:]
Java code
String str = "中国";
System.out.println(str.length()); //这些应该都没有问题,关键在下面
System.out.println(str.getBytes().length);//注意这里是得到的gbk的字节,一个汉字gbk编码是2个字节
System.out.println(new String(str.getBytes(),"UTF-8"));
//这里用得到的gbk的字节去转换成utf-8,需要注意的是一般情况下utf-8汉字占有3个字节,…
[/Quote]

讲的太透彻了,我以前看UNICODE总是看不懂,看了你的帖子真是醍醐灌顶的感觉,不过我想问一下,问什么会用GBK编码,而不是GB2312,从网上说的是从系统的参数得知的,怎么得到这个系统参数,我以前看的资料总说我们传输数据要用字节,不要用字符,这样可以避免乱码,对这个不是很理解,为什么利用字节传可以避免乱码,而利用字符传却可能避免乱码?
skyhits1921 2009-04-19
  • 打赏
  • 举报
回复
这几天忙,没顾得上看帖子。。。。
[Quote=引用 5 楼 mouyong 的回复:]
说得具体一点:
Java平台的默认编码是Unicode编码,是正规的双字节编码,也就是说,无论是ASCII码或者汉字它们都使用双字节再进行存储。

所以"中国".length()是2(这里的length()方法相当于是求有几个“字”),而"abc中国".length()是5.

而getBtyes()方法是把String转换为一个btye[]类型,而大家都只知道,一个btye就只有一个字节,所以自然"中国".getBtyes().length()是4(因为这时的length是求btye数组有几个元素,…
[/Quote]

那我想问既然你说
由于Unicode编码与UTF-8编码汉字部分是不一样的,所以在把Unicode字节当成UTF-8的“字”来看时(也就是new String("中国".getBtyes(),"UTF-8")这段代码所表达的意思),汉字总长度会减少一个汉字,而英文保持不变(具体原因百度一下就知道,这是因为两个编码的特点造成的,而楼主说不要照抄,所以我就不抄了),所以new String("中国".getBytes(),"UTF-8").lenght()输出为3,而new String("abc中国".getBytes(),"UTF-8").length()为6。
但是为什么打印new String("中国".getBytes(),"UTF-8").lenght()为3,这不是很你说的汉字总长度会减少一个汉字相违背吗?还是我理解错了?
complier199 2009-04-16
  • 打赏
  • 举报
回复
mark
lili830209 2009-04-16
  • 打赏
  • 举报
回复
mark
hbgzg3006 2009-04-16
  • 打赏
  • 举报
回复

String str = "中国";
System.out.println(str.length()); //这些应该都没有问题,关键在下面
System.out.println(str.getBytes().length);//注意这里是得到的gbk的字节,一个汉字gbk编码是2个字节
System.out.println(new String(str.getBytes(),"UTF-8"));
//这里用得到的gbk的字节去转换成utf-8,需要注意的是一般情况下utf-8汉字占有3个字节,而acsll码在utf-8中是一个字节
//而编码转换的规则是对字节进行扫描,如果可以转换成1个字节的ascll就优先转换,可以转换成2个字节就优先转换成两个字节的utf-8编码

//* 0xxxxxxx (00-7f) ascll
// * 110xxxxx 10xxxxxx (c0-df)(80-bf) ascll和汉字之间的一些字符
//* 1110xxxx 10xxxxxx 10xxxxxx (e0-ef)(80-bf)(80-bf) 汉字
//* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (f0-f7)(80-bf)(80-bf)(80-bf)
//* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (f8-fb)(80-bf)(80-bf)(80-bf)(80-bf)
//* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (fc-fd)(80-bf)(80-bf)(80-bf)(80-bf)(80-bf)
//仔细看上面的utf-8的编码表 再看通过getBytes(),最终得到的二进制码是11010110 11010000 10111001 11111010(楼主可以自己去输出以下,注意负数的转换即可)
//第一个字节与第二个一直到最后字节组合不成utf-8编码(110开始的只有上面的第二行,但是下一个字节不是10******,因此要对第一个字节单独解码
//再看第二个与第三个字节为11010000 10111001 刚好是一个上面的第二行的范围内,所以对他们两个进行一个utf-8解码
//最后对11111010 进行解码
//通过以上分析可以知道得到的utf-8时3个字符,所以长度是3
System.out.println(new String(str.getBytes(),"UTF-8").getBytes().length);

String str2 ="abc中国";
System.out.println(str2.length());
System.out.println(str2.getBytes().length);
System.out.println(new String(str2.getBytes(),"UTF-8").length());
//01100001 01100010 01100011 11010110 11010000 10111001 11111010
//一样从左到右去解码 显然前三个字节满足第一个范围分别解码为abc,后面就与上面的分析一样了
//顺便说一句,如果不想得到乱码可以用getBytes("utf-8")
System.out.println(new String(str2.getBytes(),"UTF-8").getBytes().length);
yangxiao_jiang 2009-04-16
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 mouyong 的回复:]
说得具体一点:
Java平台的默认编码是Unicode编码,是正规的双字节编码,也就是说,无论是ASCII码或者汉字它们都使用双字节再进行存储。

所以"中国".length()是2(这里的length()方法相当于是求有几个“字”),而"abc中国".length()是5.

而getBtyes()方法是把String转换为一个btye[]类型,而大家都只知道,一个btye就只有一个字节,所以自然"中国".getBtyes().length()是4(因为这时的length是求btye数组有几个元素,即有…
[/Quote]

正解。
goodmrning 2009-04-16
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 fengzhou0920 的回复:]
第一部分:
第一个:字符串长度2;
第二个:由于汉字占两个字节所以得到长度应该是4;
第三个:不知道是什么原因,我想是不是按照UTF-8编码后一个汉字就成了一个半字节。所以就是3;
的四个:再取其 byte 数组其长度就成了4;
第二部分:
第一个:字符串长度5;
第二个:同上原理所以是7;
第三个:同上原理汉字变成一个半字节,而其它的没变,所以是6;
第四个:同上原理再取其 byte 数组其长度就成了7;
[/Quote]
顶!
hbgzg3006 2009-04-16
  • 打赏
  • 举报
回复
补充点:
//对11111010进行解码,显然按照表格是没有结果的,所以结果是?可以通过这个来测试 11111010的对应的byte -6
byte []a=new byte[]{-6};
System.out.println(new String(a,"utf-8"));
//另外
System.out.println(new String(str.getBytes(),"UTF-8").getBytes().length);
//这个编译器应该做过一部分优化,getBytes后变成上面的那样的4个字节,由于utf-8解码后第一个字节不知道用utf-8编码是什么,所以维持
//原来的那个字节,后面能用utf-8编码的再进行gbk解码。最终得到长度。需注意的是utf-8跟gbk这里都是是占有两个字节。见上面的解码。
默然说话 2009-04-15
  • 打赏
  • 举报
回复
说得具体一点:
Java平台的默认编码是Unicode编码,是正规的双字节编码,也就是说,无论是ASCII码或者汉字它们都使用双字节再进行存储。

所以"中国".length()是2(这里的length()方法相当于是求有几个“字”),而"abc中国".length()是5.

而getBtyes()方法是把String转换为一个btye[]类型,而大家都只知道,一个btye就只有一个字节,所以自然"中国".getBtyes().length()是4(因为这时的length是求btye数组有几个元素,即有几个字节),而"abc中国".getBytes().length()自然是7

由于Unicode编码与UTF-8编码汉字部分是不一样的,所以在把Unicode字节当成UTF-8的“字”来看时(也就是new String("中国".getBtyes(),"UTF-8")这段代码所表达的意思),汉字总长度会减少一个汉字,而英文保持不变(具体原因百度一下就知道,这是因为两个编码的特点造成的,而楼主说不要照抄,所以我就不抄了),所以new String("中国".getBytes(),"UTF-8").lenght()输出为3,而new String("abc中国".getBytes(),"UTF-8").length()为6。


其实你只要打印一下new String("abc中国".getBytes(),"UTF-8")或者new String("中国".getBytes(),"UTF-8")就会发现,这两个新的字符串是乱码。
默然说话 2009-04-15
  • 打赏
  • 举报
回复
只是你对length()方法的理解而已。
baobao04551 2009-04-15
  • 打赏
  • 举报
回复
我觉得应该是这样吧?


String str = "中国";
System.out.println("第一部分-------------------------------------------");
System.out.println(str.length());
System.out.println(str.getBytes().length);
System.out.println(str.getBytes("UTF-8").length);
System.out.println(str.getBytes("UTF-8").length);
System.out.println("--------------------------------------------------");

String str2 ="abc中国";
System.out.println("第二部分-------------------------------------------");
System.out.println(str2.length());
System.out.println(str2.getBytes().length);
System.out.println(str2.getBytes("UTF-8").length);
System.out.println(str2.getBytes("UTF-8").length);
System.out.println("--------------------------------------------------");



如果这样的话
new String(str2.getBytes(),"UTF-8").length() 把本来unicode生成的字节数组按utf8编码,这没有进行编码转换,所以得到的结果是一个不确定的值。
baobao04551 2009-04-15
  • 打赏
  • 举报
回复
这篇文章可以看看,明白基本原理就会懂很多,顺便说一句,java默认的编码应该是unicode。
http://hi.baidu.com/dustin_xiao/blog/item/2ab75b24c27ca32ed507426f.html
GeekZFZ 2009-04-15
  • 打赏
  • 举报
回复
第一部分:
第一个:字符串长度2;
第二个:由于汉字占两个字节所以得到长度应该是4;
第三个:不知道是什么原因,我想是不是按照UTF-8编码后一个汉字就成了一个半字节。所以就是3;
的四个:再取其 byte 数组其长度就成了4;
第二部分:
第一个:字符串长度5;
第二个:同上原理所以是7;
第三个:同上原理汉字变成一个半字节,而其它的没变,所以是6;
第四个:同上原理再取其 byte 数组其长度就成了7;

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧