您当前的位置:首页 > 计算机 > 编程开发 > 安卓(android)开发

寻找字符集常量

时间:02-04来源:作者:点击数:

源码寻找字符集常量过程

做开发也有很多年了,时常会遇到使用字符集的地方,有时候就会想,使用硬编码指定字符集也太不专业了,有没有字符集的常量呢?与字符集相关的类有一个特别明显的就是Charset,这个类就代表字符集,我们很少使用它的构造方法来创建字符集,它有一些获取Charset实例对象的静态方法,如下:

在这里插入图片描述

看方法名也很容易理解其中的含义,于是从这四个静态方法中进入源码查看,找到了一些字符字符集相关的常量,它们定义在sun.nio.cs包里面,里面有各种字符集类,如GBK、UTF_8、UTF_16、ISO_8859_1、Unicode等非常非常多的字符集类,应该是包含了所有的字符集了,正兴高采烈地使用它们时,发现一运行就报错了,大概意思是这些类是不允许使用的,晕!

一次偶然的机会,翻看Android中的Charset.defaultCharsets()的源码,发现了新大陆,如下:

	public static Charset defaultCharset() {
        // Android-changed: Use UTF_8 unconditionally.
        synchronized (Charset.class) {
            if (defaultCharset == null) {
                defaultCharset = java.nio.charset.StandardCharsets.UTF_8;
            }

            return defaultCharset;
        }
    }

代码注释中有说明这是Android修改过的源码,与标准JDK的源码不一样了哦。

StandardCharsets,翻译过来就是标准字符集,但是没有GBK呀,气人,GBK不标准吗?如下:

在这里插入图片描述

经实验,这些常量可以使用。

在使用OkHttp的时候,也会涉及到字符集,所以我想OkHttp这么专业不可能用硬编码吧,于是进它源码里面找找他是用的什么样的字符集常量,关于字符集,在获取String的时候肯定是用到了的,于是可以从获取String的函数的源码入手:

response.body().string()

通过源码发现,在它的Util类里面封装了一些字符集常量,如下:

  public static final Charset UTF_8 = Charset.forName("UTF-8");
  public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
  private static final Charset UTF_16_BE = Charset.forName("UTF-16BE");
  private static final Charset UTF_16_LE = Charset.forName("UTF-16LE");
  private static final Charset UTF_32_BE = Charset.forName("UTF-32BE");
  private static final Charset UTF_32_LE = Charset.forName("UTF-32LE");

可惜,也没有GBK,哎!

后来开发用了Kotlin,Kotlin是个好东西,可以少写很多代码,比如file.readText()就可以把一个文件对象关联的文本内容全部读取出来,这里肯定也用到了字符集,点进去看源码,发现Kotlin用的是自带字符集常量,如下:

在这里插入图片描述

可惜,也没有GBK。

总结

有如下三种字符集常量可以使用:

  1. StandardCharsets.UTF_8 (JDK自带,这是JDK1.7的时候才有的)
  2. Util.UTF_8 (OkHttp自带)
  3. Charsets.UTF_8 (Kotlin自带)

个人感觉使用Kotlin自带的会比较方便,它的类名Charsets比较短也比较好记而且类名很专业。通过读别人的源码,我们也可以学到,其实可以自己定义一个类,里面放一些字符集常量,不一定非要去JDK里找,这样的话我们自己定义,还可以增加GBK常量呢,说到这里,Kotlin有扩展属性功能,我们可以给Kotlin的Charsets类扩展一个GBK属性,这样就完美了,如下:

val Charsets.GBK: Charset
    get() = Charset.forName("GBK")

fun main() {
    println(Charsets.GBK)
}

这里不用担心每次调用Charsets.GBK时都会创建新的字符集对象,因为Charset.forName()函数会缓存使用到的字符集,每次会先从缓存中取,取不到才会去创建。

最后一点,有时候传参时,可能函数接收的字符集就是一个String,而不是Charset对象,怎么办呢?Charset对象有如下三个方法可以返回它的名字:

    println(Charsets.GBK.displayName())
    println(Charsets.GBK.name())
    println(Charsets.GBK.toString())

输出都是:GBK

点源码进去看,发现toString返回的是name()函数,而name()函数和displayName()函数都是返回name属性,似乎没有区别,看看文档说明,如下:

displayName() // 返回此 charset 用于默认语言环境的可读名称。
name()        // 返回此 charset 的规范名称。

似乎name()函数比较好,因为规范嘛,绝对是可用的,而displayName保不准哪天就改源码了,如GBK编码给你返回“汉字内码扩展规范”,根据文档描述返回默认语言环境的可读名称,如果在中国,很有可能 返回汉字的描述名称嘛!

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门