寻找字符集常量

138 篇文章 3 订阅
65 篇文章 6 订阅

源码寻找字符集常量过程

做开发也有很多年了,时常会遇到使用字符集的地方,有时候就会想,使用硬编码指定字符集也太不专业了,有没有字符集的常量呢?与字符集相关的类有一个特别明显的就是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编码给你返回“汉字内码扩展规范”,根据文档描述返回默认语言环境的可读名称,如果在中国,很有可能 返回汉字的描述名称嘛!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

android_cai_niao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值