栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

字节数组与String类型转换时的默认字符集

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

字节数组与String类型转换时的默认字符集

引入:在学习javaWeb时,碰到需要将字节数组和String类型做相互转换的,如使用base64编码时。那么,我们知道String其实提供了API:getBytes() 将字符串转换为字节数组,而通过构造器new String(byte[]) 又可以将字节数组重新转化为字符串,对吧?但我们经常需要跟客户端做交互,此时很容易在这两个转换之间发生乱码问题。所以今天,我们一起来解决这个问题吧!


首先,我们需要明白,要使 字节数组 -> 字符串,或 字符串 -> 字节数组,两个过程来去自如而不乱码,就要求这两个互逆过程所使用的字符集必须统一,才能保证互相转换时不出现乱码。

对于 String.getBytes(String charsetName):可以传入参数charsetName,即字符集的名称,那么就可以根据该字符集对该字符串进行转化成字节数组。
同理,new String(byte[] buffer, String charsetName):也可以传入参数charsetName设置字符集,那么JVM就会根据该字符集将该buffer字节数组转化成一个字符串后返回。


然而,实际上呢我们可以不传入字符集参数,那么在字符串和字节数组进行相互转换时,JVM会采用平台的默认字符集对两者进行转换。而这个默认的字符集到底为何,是我们今天要讨论的重点:

  • 首先,我们先测试第一种情况,运行一个最简单的Java程序,不需要Tomcat服务器,只依赖JVM,代码如下:
public class StringTest {

    @Test
    public void test(){

        //获取当前系统的默认字符集
        System.out.println("当前系统的默认字符集:" + System.getProperty("file.encoding"));

        //测试文本
        String str = "我是测试文本";

        //使用默认字符集,对字符串和字符数组进行相互转化
        byte[] bytes = str.getBytes();

        String result = new String(bytes);

        System.out.println("转化后的结果为:" + result);

    }

}

结果截图如下:

可以看到,首先,当前系统的默认字符集是UTF-8。我们知道中国的计算机的默认字符集一般都是GBK。那么为什么我这个是UTF-8呢?
其实呢,是因为我在IDEA中设置了当前运行的这个项目的默认编码方式,为UTF-8。所以我运行时获取到的系统默认字符集就是UTF-8。

现在我改了该项目的默认编码方式为GBK,再次运行查看结果。

运行结果如下所示:

很明显,此时的系统的默认字符集已然发生了改变!而且我们还发现,这时候转发出来的字符串,仍然正确!!!

所以,我们先给出第一个结论:系统的默认字符集,即为该项目的默认编码字符集。

接着,当我们试图改变代码,按默认的字符集将字符串转化为字节数组,然后指定“UTF-8”将字节数组转化为字符串,查看运行结果如下:

结果表明,UTF-8此时不奏效,那么是为什么呢?
我们将UTF-8改成GBK,再次查看结果:

它又能行了!说明此时,如果我们不指定编码方式,那么字符串和字节数组之间的相互转化,默认采用的字符集是GBK,和我们的系统的默认字符集(也就是该项目的默认字符集) 保持一致。

那么,会不会是巧合呢?
我们将系统的字符集设置为UTF-8,然后实验如下:

  • 项目的字符集设置为UTF-8,用默认字符集将字符串转化为字节数组,仍用GBK字符集将字节数组转化为字符串,实验结果如下:

    结果再一次乱码!
  • 再来一次实验,此时指定UTF-8字符集将字节数组转化为字符串,实验结果如下:

    运行结果再一次正确了!

经过以上的四个实验,我们其实已经可以得出一个结论:
当我们在字符串和字节数组之间做转化时,若没有显式指定字符集,那么转化时会自动使用系统的默认字符集,而这个系统的默认字符集,其实就是这一整个项目的默认编码字符集,也就是System.getProperty(“file.encoding”) 的属性值。

这个结论呢,其实在JDK源码中也已经说明了:

    public String(byte bytes[]) {
        this(bytes, 0, bytes.length);
    }

这就完了?NO NO NO ! 还有更有趣的东西在后面呢!


刚刚我们是做了第一种实验,测试了只依赖JVM进行运行的最基本的Java程序。
那么接下来,我们测试下在Tomcat中运行的Java程序的情况如何:
先上代码:

public class StringServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取当前系统的默认字符集
        System.out.println("当前系统的默认字符集:" + System.getProperty("file.encoding"));

        //测试文本
        String str = "我是测试文本";

        //使用默认字符集,对字符串和字符数组进行相互转化
        byte[] bytes = str.getBytes();

        String result = new String(bytes, "UTF-8");

        System.out.println("转化后的结果为:" + result);
    }
    
}

方法体中的代码都一样,唯一的区别是这是个Servlet程序,需要依赖Tomcat容器运行。

此时呢,整个项目的编码集,是UTF-8。

OK,那么接下来,我们运行,查看结果:

项目的字符集明明是UTF-8,可运行结果却告诉我们,系统的默认字符集是GBK!是不是开始疑惑了?别急,我们开头的时候讲过,国内的计算机的默认字符集,基本都是GBK,对吧?
我们可以打开谷歌浏览器的控制台,请求服务器时,查看请求头信息,如下:

可以看到,划线一行,告诉了服务器,当前的操作系统是“windows”,而我们国内的"windows"的默认字符集,就是GBK!
所以呢,这里我们得出另一个结论:当我们的Java程序是运行在Tomcat容器上时,我们的系统默认字符集就是GBK,无关整个项目的默认编码字符集。

那么,此时的String和byte[]的相互转化,默认使用的是哪个呢?
我们将刚刚的代码,用默认字符集转化字符串成字节数组,然后指定“GBK”字符集,将字节数组再次转化为字符串,查看运行结果如下:

诶,又能行了!说明此时字符串和字节数组之间的相互转化,默认采用的字符集是GBK,也就是仍然和系统的默认字符集即 System.getProperty(“file.encoding”) 的属性值保持一致。


OK,那么所有的实验都演示完毕,收最后的结论:
无论是运行在Tomcat上的Java程序,还是只运行在JVM上的普通Java程序,他们在进行字符串和字节数组的相互转换过程中,若没有显式指定字符集,那么它们会采用系统的默认字符集。
其中,运行在Tomcat容器的Java程序使用的系统字符集是GBK;
而只运行在JVM上的普通Java程序使用的系统字符集呢,与该Java项目的整体字符集保持一致。



重中之重:但不管该Java程序是运行在Tomcat还是只运行在JVM,可以确定的一点就是,它使用的系统默认字符集,就是System.getProperty(“file.encoding”)的属性值!!!

好了,以上就是我个人对本次内容的理解,如果有什么不恰当的地方,还望各位兄弟在评论区指出哦。
如果这篇文章对你有帮助的话,不妨点个关注吧~
期待下次我们共同讨论,一起进步~

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/298228.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号