zoukankan      html  css  js  c++  java
  • java的编码问题详解

    ucenter的中文问题终于解决,这也暴露我对Java编码知识的严重不足,经过多次试验和搜索,对这块知识终于有了一个新的认识,所以把理解的内容写道这里

    1:JVM的内存中字符串的编码格式是统一的吗?

    JVM里面的任何字符串资源都是Unicode,String相当于 char[] 。 而JVM中的byte[]是带编码的,比如,Big5,GBK,GB2312,UTF-8之类的。一个GBK编码的byte[] 转换成 String,

    其实就是从GBK编码向Unicode编码转换。一个String转换成一个Big5编码的byte[],其实就是从Unicode编码向Big5编码转换。所以,Unicode是所有编码转换的中间介质。所有的编码都有一个转换器可以转换到Unicode,而Unicode也可以转换到其他所有的编码。

    这个做个测试

    public class CodeTest {
    
        @Test
        public void test() throws UnsupportedEncodingException {
            String str="I am 高兴";
            System.out.println(str);
        }
    }

    在debug中显示'高'的值我39640,为该中文字符的unicode的编码,Java中的char是2个字节的。 

    2:源文件的编码对编译的影响。

    这里我专门使用了Javac和Java两个命令来做个这个试验,源码如下:

    public class CodeTest
    {
    public static void main (String[] args)
    {
    String str="高兴";
    System.out.println(str);
    }
    }

    这个源码我在UE里面把他转成GBK的,编译没有问题。但是转成UTF-8格式,就出现了问题:”楂樺叴“ ,

    public class CodeTest {
    
        @Test
        public void test() throws UnsupportedEncodingException {
    //        String str="I am 君山";
    //        System.out.println(str);
            String str="高兴";
            str=new String(str.getBytes("UTF-8"),"GBK");
            System.out.println(str);
        }
    }

    str的值为”楂樺叴“。说明源文件的编码对编译时有影响的。GBK为本地系统的编码。Javac在编译过程中把UTF-8的转成了GBK.  下面一段是解释:

     Java编译器在对源文件编译前,首先会源文件转换为unicode编码,然后再进行编译。例如:我们的源文件是以UTF-8的方式保存的,而在编译时编译器却把它当作是用GBK方式保存的,这样编译器就会按照GBK->Unicode的编码转换方法对源文件进行转换,然后再编译,这样当然会出错,实际上编译器应当按照UTF-8->Unicode的编码转换方法来对源文件进行转换。 

    常我们手动建立一个java文件Demo.java,并保存。此时Demo.java文件的编码为ANSI,中文操作系统下就是GBK.然后使用javac命令来编译该源文件。”javac Demo.java”。Javac也需要读取java文件,那么javac是使用什么编码来解码我们读取的字节呢?其实javac采用了操作系统默认的GBK编码解码我们读取的字节,这个编码正好也是Demo.java文件的编码,二者一致,所以不会出现乱码情况。让我们来做点手脚,在保存Demo.java文件时,我们选择UTF-8保存。此时Demo.java文件编码就是UTF-8了。我们再使用”javac Demo.java”来编译,如果Demo.java里含有中文字符,此时控制台会出现警告信息,也出现了乱码。究其原因,就是因为javac采用了GBK编码解码我们读取的字节。因为我们的字节是UTF-8编码的,所以会出现乱码。如果不信的话你可以自己试试。那么解决办法呢?解决办法就是使用javac的encoding参数来制定我们的解码编码。如下:javac -encoding UTF-8 Demo.java。这里我们指定了使用UTF-8来解码读取的字节,由于这个编码和Demo.java文件编码一致,所以不会出现乱码情况了。

    3:String的编码和解码

    String对象的getBytes()可以对字符串进行编码转化成byte数组。

     public static void encode() {  
            String name = "I am 君山"; 
            toHex(name.toCharArray()); 
            try { 
                byte[] iso8859 = name.getBytes("ISO-8859-1"); 
                toHex(iso8859); 
                byte[] gb2312 = name.getBytes("GB2312"); 
                toHex(gb2312); 
                byte[] gbk = name.getBytes("GBK"); 
                toHex(gbk); 
                byte[] utf16 = name.getBytes("UTF-16"); 
                toHex(utf16); 
                byte[] utf8 = name.getBytes("UTF-8"); 
                toHex(utf8); 
            } catch (UnsupportedEncodingException e) { 
                e.printStackTrace(); 
            } 
     }

    默认使用系统编码。

    String(byte[],charset)这是对字节数组进行解码。这个是经常容易出问题的地方,你使用gbk编码,却使用utf-8解码,那么生成的String的unicode的编码已经变了。字节数组通过编码映射到指定的字符,然后这些字符转成unicode编码转成

    解码的黑洞问题:

    将中文和中文符号经过不支持中文的 ISO-8859-1 编码后,所有字符变成了“?”,这是因为用 ISO-8859-1 进行编解码时遇到不在码值范围内的字符时统一用 3f 表示,这也就是通常所说的“黑洞”,所有 ISO-8859-1 不认识的字符都变成了“?”。

  • 相关阅读:
    基于Live555实现RtspServer及高清高分辨率和高码率视频传输优化
    [开源]基于ffmpeg和libvlc的视频剪辑、播放器
    Android流媒体开发之路二:NDK C++开发Android端RTMP直播推流程序
    MP4大文件虚拟HLS分片技术,避免服务器大量文件碎片
    Android流媒体开发之路一:Camera2采集摄像头原始数据并手动预览
    DXGI快速截屏录屏技术
    一个RtspServer的设计与实现和RTSP2.0简介
    调用Live555接收RTSP直播流,转换为Http Live Streaming(iOS直播)协议
    抛开flash,自己开发实现C++ RTMP直播流播放器
    RTSP协议转换RTMP直播协议
  • 原文地址:https://www.cnblogs.com/gaoxing/p/4372638.html
Copyright © 2011-2022 走看看