java中的字符集使用什么编码,java中的字符集与编码

这是《Java与MySQL字符集与编码》 第三篇。本篇主要是从Java编码、内外码、string编码、io编码、jdbc 编码 这几个方面,讲一下Java相关的编码问题。这篇内容稍微有点多,耐心点~

1 系统编码

为什么要提系统编码呢? 因为这涉及到后面Java默认编码的问题。在Java 编译、运行时,如果没有设置编码,会默认读取系统编码。

Mac上查看编码是这么来操作的:

45ef63d76d069375e7b007eba1aae625.png

2 内码与外码,以及转换

引用个概念。

内码 & 外码

内码 :程序内部使用的字符编码,特别是某种语言实现其 char 或 String 类型在内存里用的内部编码。Java 的内码就是 UTF-16。

外码 :程序与外部交互时外部使用的字符编码。简单的来说就是除了内码都可以认为是“外码”(包括 class 文件的编码)。

复制代码

如概念所述,Java的内码是UTF-16, 而外码则是需要根据不同的场景进行设置的。

数据到达Java之后,真正需要处理的时候,就需要转换成UTF-16内码进行了。包括下面的讨论也都是在讨论外码。

3 Java在跟编码相关的两个参数

java 中跟编码相关的系统参数有如下两个:

file.encoding

sun.jnu.encoding

复制代码

我们这篇文章只讲一下 file.encoding 。

3.1 file.encoding 是什么?

文件编码。

Java源码中,有四个类调用了file.encoding 这个属性:

(1)java.nio.Charset.defaultCharset()

默认字符集是在 java 虚拟机启动时决定的,依赖于 java 虚拟机所在的操作系统的区域以及字符集。

从代码中可以看出,默认字符集就是从 file.encoding 这个属性中获取的。

此处的默认字符集会影响字符串、文件字符流读写等的默认编码。

复制代码

(2) URLEncoder.encode(String) Web环境中最常遇到的编码使用。

(3)com.sun.org.apache.xml.internal.serializer.Encoding.getMimeEncodings(String) 影响对无编码设置的xml文件的读取 。

(4)javax.print.DocFlavor影响打印的编码。

从如上信息可以得到:

file.encoding 会影响无指定编码的字符串、读写文件、URL编码、打印等内容。

3.2 file.encoding 未指定时,默认编码是什么?

应用里面,在部署的时候如果指定了-Dfile.encoding=UTF-8类似的设定,那么后续的默认编解码就是用这个值,如果没有设定,则使用系统的编解码方案。

来段代码:

import java.nio.charset.Charset;

public class Main{

public static void main(String[] args) {

System.out.println("i am a 中国人");

System.out.println(Charset.defaultCharset().name());

System.out.println(System.getProperty("sun.jnu.encoding"));

System.out.println(System.getProperty("file.encoding"));

}

}

复制代码

编译一下: javac Main.java

然后执行: java Main. 看下结果

b454bf683f2c810976c1d48693b0b4f4.png

stackoverflow上面关于默认编码 有个经典的回答,stackoverflow.com/questions/3… 。

大意是

在Java进程启动之后,默认字符集 就确定了,后续即使使用 System.setProperty("file.encoding", "UTF-8"); 修改,只会修改配置项值 Charset.defaultCharset()的值,但是实际解码的时候,还是使用了系统初始化的编解码方案,不会改变默认字符集编码。

如果需要指定读取文件内容的编码,需要通过字符流的构造器InputStreamReader(InputStream in, Charset cs)设置。

还是上面的代码,那我们在jvm启动时指定一下file.encoding 看下.

9d3716e2bcf2c3d913dec1e3e957a47e.png

发现 Charset.defaultCharset().name() 已经变成了GBK.并且输出也乱码了。这是因为编码的时候使用了GBK,而输出到系统item窗口时我们是按照UTF-8解码的,所以就乱码了。

我们再试下通过system来改一下编码,看看是不是stackoverflow 上所说的那样。

import java.nio.charset.Charset;

public class Main{

public static void main(String[] args) {

System.setProperty("file.encoding", "UTF-8"); // 设置file.encoding

System.out.println("i am a 中国人");

System.out.println(Charset.defaultCharset().name());

System.out.println(System.getProperty("sun.jnu.encoding"));

System.out.println(System.getProperty("file.encoding"));

}

}

复制代码

编译 javac Main.java

运行时指定 java -Dfile.encoding=GBK Main

7f977393a1f92e9fcbd1c43bb318a317.png

我们发现,虽然程序的第一行就是设定编码为UTF-8,但是实际的编码还是GBK,这一点跟stackoverflow上一致。 而Charset.defaultCharset 也是gbk , 跟启动时指定的参数一致,这一点跟stackoverflow 上不一致。我用的java version "1.8.0_201" ,也可能跟我的版本有关系,这个暂时就不纠结了。

3.3 指定file.encoding 会产生什么影响?

file.encoding 对string的影响,我们在第4部分讲string 时进行验证。

file.encoding对读写文件内容的影响,我们这篇文章中就先不讲了,可以直接参考 www.jianshu.com/p/7688863e3… 这篇文章。

4 Java 中string 编码问题

灵魂三问 + 长度问题 + file.encoding 对string 的影响。

4.1 string 是什么

string 本身就是一个char数组,那么要表示成字节数组,就得涉及编码问题。

下面我们看几个关于string字符编码的知识点。

4.2 string 从哪儿来, 到哪儿去

我们先看一段代码,里面涉及到几种不同编码6f18c0c7043233df38e8f51803ecd691.png

看下输出:

291e6fd7c18008e510f45d64ca8c1bb4.png

这段代码中主要阐述string是通过字节数组 + 字符编码来生成的。里面讲了三种编码。由于系统默认的编码是UTF-8, 其实上面一段代码底层是这样来操作的【这就是file.encoding 对无编码string的影响】。

79102f4e10d67d1f7498e0ac5d016cb4.png

通过getBytes 获取了字符串的字节数组,然后按照UTF-8编码重新定义一个新的string用于输出,肯定只有utf-8 的能正常数据。

我们改一下new String 的编码,再来看下:

a5c86cdb01a40ba7983890919628f142.png

结果都正常了:

253e98ba5622b70828279534f5aaa552.png

4.3 string 的长度

关于string的长度,我们最常用的一个函数是string.length(), 你真的懂它的真实用途吗?

先来一个demo吧

try {

String s = new String("iam中国人");

System.out.println("========s======= " + s);

System.out.println("length: " + s.length());

System.out.println("codePointCount: " + s.codePointCount(0, s.length()));

String s2 = "\uD834\uDD1E";

System.out.println("========s2======= " +s2);

System.out.println("length: " + s2.length());

System.out.println("codePointCount: " + s2.codePointCount(0, s2.length()));

String s3 = "\uD83D\uDE02";

System.out.println("========s3======= " +s3);

System.out.println("length:" + s3.length());

System.out.println("codePointCount: " + s3.codePointCount(0, s3.length()));

} catch (Exception e) {

System.out.println(e);

}

复制代码

结果是这样的:

6e2bbacf4fe7f2048fdbe7eae6a4c204.png

从结果我们可以看出,length 跟 codePointCount 返回的结果有时相同,有时不同。

那我先看下二者的区别。

length 是返回代码单元的个数。这就是为什么s1返回了6 ,而s2跟s3 返回了2 而不是1. 因为音乐符号跟表情虽然是一个符号,但是其码元是2.

63f1c73c1c89a770c0f3134040b043a3.png

而codePointCount 是码点的个数,一个字符在字符集中肯定只对应一个码点,所以就是结果中的6、1、1.1d1af7ca68ae8da2b9fb88934c64782a.png

5 Java中的IO编码问题

如前文所述,Java中跟字符编码比较相关的,除了string就是IO了,这篇文章我们先不讲,等后续有时间再细讲。如果感兴趣可以直接看 xiaogd.net/category/字符… 相关的文章。

6 spring boot 中jdbc编码设置

上面讲完了Java中对字符集、编码的介绍,那这部分为我们下一节讲MySQL编码做个铺垫。

Java里面跟MySQL交互,主要涉及编码的地方就是jdbc 。spring 中涉及JDBC的编码是

d2ace546e239079533ce508ccd4f2b97.png

这部分我们就先不写demo了,在下一篇文章中,讲解MySQL编码时,会写详细的demo。

7 总结

本文主要讲解了Java中的编码问题(IO的没讲),file.encoding 的知识,重点讲了string的编码问题。最后提到了jdbc的编码问题,为我们下一节的MySQL编码问题做个铺垫。

8 参考文献

java运行时参数file.encoding和sun.jnu.encoding详解:

www.jianshu.com/p/7688863e3…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大学生参加学科竞赛有着诸多好处,不仅有助于个人综合素质的提升,还能为未来职业发展奠定良好基础。以下是一些分析: 首先,学科竞赛是提高专业知识和技能水平的有效途径。通过参与竞赛,学生不仅能够深入学习相关专业知识,还能够接触到最新的科研成果和技术发展趋势。这有助于拓展学生的学科视野,使其对专业领域有更深刻的理解。在竞赛过程,学生通常需要解决实际问题,这锻炼了他们独立思考和解决问题的能力。 其次,学科竞赛培养了学生的团队合作精神。许多竞赛项目需要团队协作来完成,这促使学生学会有效地与他人合作、协调分工。在团队合作,学生们能够学到如何有效沟通、共同制定目标和分工合作,这对于日后进入职场具有重要意义。 此外,学科竞赛是提高学生综合能力的一种途径。竞赛项目通常会涉及到理论知识、实际操作和创新思维等多个方面,要求参赛者具备全面的素质。在竞赛过程,学生不仅需要展现自己的专业知识,还需要具备创新意识和解决问题的能力。这种全面的综合能力培养对于未来从事各类职业都具有积极作用。 此外,学科竞赛可以为学生提供展示自我、树立信心的机会。通过比赛的舞台,学生有机会展现自己在专业领域的优势,得到他人的认可和赞誉。这对于培养学生的自信心和自我价值感非常重要,有助于他们更加积极主动地投入学习和未来的职业生涯。 最后,学科竞赛对于个人职业发展具有积极的助推作用。在竞赛脱颖而出的学生通常能够引起企业、研究机构等用人单位的关注。获得竞赛奖项不仅可以作为个人履历的亮点,还可以为进入理想的工作岗位提供有力的支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值