一句话彻底明白java乱码问题

5 篇文章 0 订阅

相信java的中文编解码问题是让许多java开发者头疼的问题,一旦遇到坑就会在GBK和UTF-8之间纠结。

我有两次痛苦的经历,一次是和另一个公司的C++平台传数据,调接口的时候因为中文乱码耽误了好多功夫,这一次是用MD5加密微信支付签名的时候在开发环境和在生产环境MD5加密结果竟然不一样,在生产环境上反复打补丁抓日志最后定位到是getBytes()中文编码问题造成的,所有这次决定彻底弄明白这个问题。

         一开始的想法是UTF-8和GBK互转,后来各种查之后发现,他俩完全是两回事,UTF-8是UNICODE编码方式的一种表现形式,而GBK就是GBK编码,例如“汉”的Unicode编码值是6C49,而GB码是BABA,至于几个字节并不是关键,可以这么认为,他们是不兼容的。就像要把一本英文书翻译成中文书,并不是调一下new String()  getBytes()重新编码一下就可以的。要是真要转换需要调用软件包或者API之类的字典。

          但是,我们乱码的根源是什么呢,其实多数的乱码不是这个原因。看了String.getBytes()的源代码中有Charset.defaultCharset().name(),然后这个又取自于GetPropertyAction("file.encoding"),然后搜了一下java file.encoding,有人回答在jvm启动或者tomcat的catalina里加上配置 -Dfile.encoding=UTF-8就可以。

这个设置其实是指定了jvm的Charset.defaultCharset(),也就是默认编码方式,这个值只初始化一次,如果不设置,jvm就会取操作系统的编码方式。

            但是为什么设了这个就可以解决乱码了呢,设了这个有什么用呢?为什么设置配置 -Dfile.encoding=UTF-8而不设置配置 -Dfile.encoding=GBK呢,有一句话提醒了我,就是在设置哪种编码方式的前提是你知道你的字符串的源头是什么编码方式。这也就解答了所有乱码的原因,也就是乱码的原因就是我们没有按照这个字符串的源头的编码方式使用或者传输。字符串常见的源头有:java源代码或者可以说class文件,数据库数据,文件等,当我们在源头定义一个字符串的时候我们肯定是以某种编码方式对他编码的,因为字符只有编码才能保存到电脑,我们只要记住,在源头怎么编码的我们就怎么使用这个字符串就肯定不会有问题。例如,我在java代码中定义一个字符串 String str = "hello我是一个字符串"; 我们的java文件一般都是用UTF-8保存,假如我们在windows生产环境上运行代码的时候,用到了对这个字符串MD5加密,其中会调用str.getBytes(),这里使用getBytes()的时候我们没有明确指定编码方式也没有配置jvm -Dfile.encoding,这个时候jvm会取系统默认编码方式GBK,相当于调用了str.getBytes("GBK"); 一个源头是UTF-8的字符串我们以GBK的方式使用,无论你怎么转换都是错误的,反之同理。

       数据库和文件中的字符也是同样的道理,例如我们java平台在数据库中取数据传输给C++平台,如果我们的数据库字符是GBK正常显示的编码,那么我们传输给C++平台的时候就以GBK的方式解码传给他,C++端拿到之后也要以GBK方式编码之后才能正常显示。

        明白了这个道理我们知道设置了jvm -Dfile.encoding=UTF-8解决了乱码问题是因为你字符的源头是UTF-8的,我们在getBytes()的时候指定正确的编码方式效果也是一样的。另外包括在JSP、HTML、txt等所有涉及字符编码方式的地方都是同样的道理,我们以什么样的编码方式正确使用字符取决于他的源头。

        所以,彻底解决这个问题的方法就是,我们要知道字符串的源头是什么编码方式,并且以源头的编码方式使用和传输字符。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值