Java 字符编码与解码:深入理解 Charset 类

目录

引言

一、什么是字符集(Charset)?

二、Charset 类的核心功能

1. 获取字符集实例

2. 编码与解码

示例1:字符串转字节数组

示例2:处理不同字符集的乱码问题

3. 字符集检测与支持

三、Charset 类的常用方法

1. 静态方法

(1)static Charset forName(String charsetName)

(2) static Charset defaultCharset()

(3) static boolean isSupported(String charsetName)

(4) static SortedMap availableCharsets()

2. 实例方法

(1) String name()

(2) Set aliases()

(3) String displayName()

(4) boolean canEncode()

(5) ByteBuffer encode(CharBuffer cb)

(6) CharBuffer decode(ByteBuffer bb)

(7) CharsetEncoder newEncoder()

(8) CharsetDecoder newDecoder()

四、 常见使用场景

五、注意事项


引言

在软件开发中,字符编码(Character Encoding)是处理文本数据的关键环节。无论是读写文件、网络通信,还是数据库存储,字符编码错误都可能导致乱码问题。Java 提供了 java.nio.charset.Charset 类,用于统一管理字符集和编码规则。本文将深入探讨 Charset 类的核心功能,并通过代码示例演示其实际应用。


一、什么是字符集(Charset)?

字符集(Charset)定义了字符(如字母、数字、符号)与二进制数据之间的映射规则。常见的字符集包括:

  • UTF-8:变长编码,兼容 ASCII,支持全球所有语言,互联网首选。

  • GBK:中文扩展编码,兼容 GB2312。

  • ISO-8859-1:单字节编码,覆盖西欧语言。

  • UTF-16:定长或变长编码,Java 内部字符串存储的默认方式。


二、Charset 类的核心功能

Charset 类位于 java.nio.charset 包中,主要用途包括:

1. 获取字符集实例

Java 支持两种方式获取字符集对象:

// 方式1:通过名称获取(推荐)
Charset utf8 = Charset.forName("UTF-8");// 方式2:通过标准字符集常量
Charset gbk = StandardCharsets.GBK;

2. 编码与解码

编码(Encode)是将 String 转换为 byte[],解码(Decode)则是反向过程。

示例1:字符串转字节数组

String text = "你好,世界!";
Charset charset = Charset.forName("UTF-8");// 编码
byte[] bytes = text.getBytes(charset); // 解码
String decodedText = new String(bytes, charset);
System.out.println(decodedText); // 输出:你好,世界!

示例2:处理不同字符集的乱码问题

String original = "Hello, 中国!";
byte[] gbkBytes = original.getBytes(StandardCharsets.GBK);// 错误解码(用UTF-8解码GBK字节)
String wrongText = new String(gbkBytes, StandardCharsets.UTF_8);
System.out.println(wrongText); // 输出乱码:Hello, �й���

3. 字符集检测与支持

通过 Charset 类可以检测当前 JVM 支持的字符集:

// 获取所有可用字符集
Map<String, Charset> charsets = Charset.availableCharsets();
charsets.forEach((name, cs) -> System.out.println(name));

三、Charset 类的常用方法

1. 静态方法

(1)static Charset forName(String charsetName)

该方法根据指定的字符集名称返回对应的 Charset 对象。如果指定的字符集名称不被支持,会抛出 UnsupportedCharsetException 异常。

  • 作用:通过字符集名称获取对应的 Charset 实例。

  • 示例

import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;public class CharsetForNameExample {public static void main(String[] args) {try {Charset utf8 = Charset.forName("UTF-8");System.out.println("获取到的字符集: " + utf8);} catch (UnsupportedCharsetException e) {System.out.println("不支持的字符集: " + e.getMessage());}}
}

(2) static Charset defaultCharset()

作用defaultCharset() 方法用于返回 Java 虚拟机(JVM)实例的默认字符集。(由系统属性 file.encoding 决定)。默认字符集是在 JVM 启动时根据底层操作系统的默认字符编码来确定的。

方法签名

public static Charset defaultCharset()

返回值

该方法返回一个 Charset 对象,表示 JVM 的默认字符集。

示例

import java.nio.charset.Charset;public class DefaultCharsetExample {public static void main(String[] args) {// 获取默认字符集Charset defaultCharset = Charset.defaultCharset();System.out.println("默认字符集: " + defaultCharset.name());// 可以使用默认字符集进行编码和解码操作String text = "你好,世界!";byte[] encodedBytes = text.getBytes(defaultCharset);String decodedText = new String(encodedBytes, defaultCharset);System.out.println("编码后的字节数组长度: " + encodedBytes.length);System.out.println("解码后的文本: " + decodedText);}
}

运行结果:

代码解释

  1. 获取默认字符集:通过调用 Charset.defaultCharset() 方法获取 JVM 的默认字符集,并将其存储在 defaultCharset 变量中。
  2. 打印默认字符集名称:使用 defaultCharset.name() 方法获取默认字符集的名称并打印。
  3. 编码操作:使用 text.getBytes(defaultCharset) 方法将字符串 text 按照默认字符集进行编码,得到字节数组 encodedBytes
  4. 解码操作:使用 new String(encodedBytes, defaultCharset) 方法将字节数组 encodedBytes 按照默认字符集进行解码,得到字符串 decodedText
  5. 打印编码后的字节数组长度和解码后的文本:分别打印编码后的字节数组长度和解码后的文本。

(3) static boolean isSupported(String charsetName)

作用:该方法用于判断 Java 虚拟机(JVM)是否支持指定名称的字符集。字符集名称可以是标准的字符集名称,如 "UTF-8""GBK""ISO-8859-1" 等,也可以是字符集的别名。

方法签名

public static boolean isSupported(String charsetName)
  • 参数charsetName 是一个字符串,表示要检查的字符集名称。
  • 返回值:如果 JVM 支持指定名称的字符集,返回 true;否则返回 false

示例:

import java.nio.charset.Charset;public class CharsetSupportExample {public static void main(String[] args) {// 检查常见字符集是否被支持String[] charsetNames = {"UTF-8", "GBK", "ISO-8859-1", "NonExistentCharset"};for (String charsetName : charsetNames) {boolean isSupported = Charset.isSupported(charsetName);if (isSupported) {System.out.println(charsetName + " 字符集被支持。");} else {System.out.println(charsetName + " 字符集不被支持。");}}}
}

运行结果:

代码解释

  1. 定义字符集名称数组:创建一个包含多个字符集名称的字符串数组 charsetNames,其中包括常见的支持的字符集(如 "UTF-8""GBK""ISO-8859-1")以及一个不存在的字符集名称 "NonExistentCharset"
  2. 遍历字符集名称数组:使用 for-each 循环遍历数组中的每个字符集名称。
  3. 检查字符集是否被支持:对于每个字符集名称,调用 Charset.isSupported(charsetName) 方法来检查 JVM 是否支持该字符集,并将结果存储在 isSupported 变量中。
  4. 输出检查结果:根据 isSupported 的值,打印相应的信息,表明该字符集是否被支持。

注意事项

  • 字符集名称是大小写不敏感的。例如,"UTF-8" 和 "utf-8" 被视为相同的字符集名称。
  • 当需要在代码中使用特定字符集时,建议先使用 isSupported 方法检查该字符集是否被支持,以避免在不支持的字符集上进行操作而抛出异常。如果字符集不被支持,可以采取适当的处理措施,如选择其他支持的字符集。

(4) static SortedMap<String, Charset> availableCharsets()

该方法用于获取 Java 虚拟机(JVM)当前支持的所有字符集的映射。返回的是一个 SortedMap,其中键(String 类型)是字符集的规范名称,值(Charset 类型)是对应的 Charset 对象。由于返回的是 SortedMap,所以这些字符集名称会按照字典序进行排序。

作用:返回当前 JVM 支持的所有字符集(按名称排序)。

方法签名

public static SortedMap<String, Charset> availableCharsets()

返回值:一个 SortedMap<String, Charset>,包含了 JVM 支持的所有字符集,键为字符集的规范名称,值为对应的 Charset 对象

示例:

import java.nio.charset.Charset;
import java.util.Map;
import java.util.SortedMap;public class AvailableCharsetsExample {public static void main(String[] args) {// 获取 JVM 支持的所有字符集SortedMap<String, Charset> availableCharsets = Charset.availableCharsets();// 遍历字符集映射for (Map.Entry<String, Charset> entry : availableCharsets.entrySet()) {String charsetName = entry.getKey();Charset charset = entry.getValue();System.out.println("字符集规范名称: " + charsetName);System.out.println("  别名: " + charset.aliases());}}
}

运行结果:

代码解释

  1. 获取支持的字符集:调用 Charset.availableCharsets() 方法获取 JVM 支持的所有字符集的映射,并将其存储在 availableCharsets 变量中。
  2. 遍历字符集映射:使用 for-each 循环遍历 availableCharsets 中的每个键值对。对于每个键值对,获取字符集的规范名称(键)和对应的 Charset 对象(值)。
  3. 输出字符集信息:打印字符集的规范名称,并通过 charset.aliases() 方法获取该字符集的别名并打印。

注意事项

  • 线程安全:该方法是线程安全的,可以在多线程环境中调用。
  • 结果依赖于 JVM 实现:不同的 JVM 实现可能支持不同的字符集,所以调用该方法返回的结果可能会因 JVM 不同而有所差异。
  • 使用场景:当你需要动态了解当前 JVM 支持哪些字符集,或者需要根据用户输入的字符集名称来选择合适的字符集时,可以先使用该方法获取支持的字符集列表,再进行相应的处理。

2. 实例方法

(1) String name()
  • 作用:返回字符集的规范名称(如 UTF-8)。

  • 示例

String name = utf8.name(); // "UTF-8"
(2) Set<String> aliases()
  • 作用:返回字符集的所有别名(如 UTF-8 的别名可能包含 UTF8)。

  • 示例

    Set<String> aliases = utf8.aliases();
(3) String displayName()
  • 作用:返回字符集的本地化显示名称。

  • 示例

    String displayName = utf8.displayName();
(4) boolean canEncode()
  • 作用:检查字符集是否支持编码(绝大多数字符集支持)。

  • 示例

    boolean canEncode = utf8.canEncode();
(5) ByteBuffer encode(CharBuffer cb)
  • 作用:将字符缓冲区编码为字节缓冲区。

  • 示例

    CharBuffer charBuffer = CharBuffer.wrap("Hello");
    ByteBuffer byteBuffer = utf8.encode(charBuffer);
(6) CharBuffer decode(ByteBuffer bb)
  • 作用:将字节缓冲区解码为字符缓冲区。

  • 示例

    ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[]{72, 101, 108, 108, 111});
    CharBuffer charBuffer = utf8.decode(byteBuffer);
(7) CharsetEncoder newEncoder()
  • 作用:创建字符集的编码器(更精细控制编码过程)。

  • 示例

    CharsetEncoder encoder = utf8.newEncoder();
(8) CharsetDecoder newDecoder()
  • 作用:创建字符集的解码器(更精细控制解码过程)。

  • 示例

    CharsetEncoder encoder = utf8.newEncoder();

四、 常见使用场景

  1. 文件读写:指定字符集读取或写入文本文件。

    Path path = Paths.get("file.txt");
    List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
  2. 网络传输:确保客户端和服务端使用相同字符集编码数据。

    byte[] data = "发送数据".getBytes(StandardCharsets.UTF_8);
  3. 字符串与字节数组互转

    String str = new String(bytes, StandardCharsets.UTF_8);
    byte[] bytes = str.getBytes(StandardCharsets.UTF_8);

五、注意事项

  • 字符集名称不区分大小写:例如 UTF-8 和 utf-8 是等价的。

  • 默认字符集依赖环境defaultCharset() 的结果可能因操作系统或 JVM 设置不同而不同。

  • 非法字符集名称:使用 forName() 时,如果字符集不存在会抛出 UnsupportedCharsetException

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/17075.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis7.0八种数据结构底层原理

导读 本文介绍redis应用数据结构与物理存储结构,共八种应用数据结构和 一. 内部数据结构 1. sds sds是redis自己设计的字符串结构有以下特点: jemalloc内存管理预分配冗余空间二进制安全(c原生使用\0作为结尾标识,所以无法直接存储\0)动态计数类型(根据字符串长度动态选择…

本地Deepseek-r1:7b模型集成到Google网页中对话

本地Deepseek-r1:7b网页对话 基于上一篇本地部署的Deepseek-r1:7b&#xff0c;使用黑窗口对话不方便&#xff0c;现在将本地模型通过插件集成到Google浏览器中 安装Google插件 在Chrome应用商店中搜索page assis 直接添加至Chrome 修改一下语言 RAG设置本地运行的模型&#…

【设计模式】【行为型模式】观察者模式(Observer)

&#x1f44b;hi&#xff0c;我不是一名外包公司的员工&#xff0c;也不会偷吃茶水间的零食&#xff0c;我的梦想是能写高端CRUD &#x1f525; 2025本人正在沉淀中… 博客更新速度 &#x1f44d; 欢迎点赞、收藏、关注&#xff0c;跟上我的更新节奏 &#x1f3b5; 当你的天空突…

gitlab Webhook 配置jenkins时“触发远程构建 (例如,使用脚本)”报错

报错信息&#xff1a; <html> <head> <meta http-equiv"Content-Type" content"text/html;charsetISO-8859-1"/> <title>Error 403 No valid crumb was included in the request</title> </head> <body><h2…

AI赋能前端开发:薪资潜力无限的未来

在当今竞争激烈的就业市场&#xff0c;掌握AI写代码工具等AI技能已经成为许多专业人士提升竞争力的关键。尤其在快速发展的前端开发领域&#xff0c;AI的应用更是日新月异&#xff0c;为开发者带来了前所未有的机遇。高薪职位对熟练掌握AI技术的前端开发者的需求与日俱增&#…

外包干了4年,技术退步太明显了。。。。。

先说一下自己的情况&#xff0c;本科生生&#xff0c;20年通过校招进入武汉某软件公司&#xff0c;干了差不多4年的功能测试&#xff0c;今年国庆&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能…

平面与平面相交算法杂谈

1.前言 空间平面方程&#xff1a; 空间两平面如果不平行&#xff0c;那么一定相交于一条空间直线&#xff0c; 空间平面求交有多种方法&#xff0c;本文进行相关讨论。 2.讨论 可以联立方程组求解&#xff0c;共有3个变量&#xff0c;2个方程&#xff0c;而所求直线有1个变量…

【状态空间方程】对于状态空间方程矩阵D≠0时的状态反馈与滑模控制

又到新的一年啦&#xff0c;2025新年快乐~。前几个月都没更新&#xff0c;主要还是因为不能把项目上的私密工作写进去&#xff0c;所以暂时没啥可写的。最近在山里实习&#xff0c;突然想起年前遗留了个问题一直没解决&#xff0c;没想到这两天在deepseek的加持下很快解决了&am…

LearningFlow:大语言模型城市驾驶的自动化策略学习工作流程

25年1月来自香港科技大学广州分校的论文“LearningFlow: Automated Policy Learning Workflow for Urban Driving with Large Language Models”。 强化学习 (RL) 的最新进展表明其在自动驾驶领域具有巨大潜力。尽管前景光明&#xff0c;但诸如手动设计奖励函数和复杂环境中的…

大语言模型多代理协作(MACNET)

大语言模型多代理协作(MACNET) Scaling Large-Language-Model-based Multi-Agent Collaboration 提出多智能体协作网络(MACNET),以探究多智能体协作中增加智能体数量是否存在类似神经缩放定律的规律。研究发现了小世界协作现象和协作缩放定律,为LLM系统资源预测和优化…

【OpenCV】双目相机计算深度图和点云

双目相机计算深度图的基本原理是通过两台相机从不同角度拍摄同一场景&#xff0c;然后利用视差来计算物体的距离。本文的Python实现示例&#xff0c;使用OpenCV库来处理图像和计算深度图。 1、数据集介绍 Mobile stereo datasets由Pan Guanghan、Sun Tiansheng、Toby Weed和D…

PT8032 3 通道触摸 IC

1. 概述 PT8032 是一款电容式触摸控制 ASIC &#xff0c;支持 3 通道触摸输入 ,2 线 BCD 码输出。具有低功耗、 高抗干扰、宽工作电压范围、高穿透力的突出优势。 2. 主要特性 工作电压范围&#xff1a; 2.4~5.5V 待机电流约 9uAV DD5V&CMOD10nF 3 通道触…

像指针操作、像函数操作的类

像指针一样的类。把一个类设计成像一个指针。什么操作符运用到指针上&#xff1f; 使用标准库的时候&#xff0c;里面有个很重要的东西叫容器。容器本身一定带着迭代器。迭代器作为另外一种智能指针。迭代器指向容器里的一个元素。迭代器用来遍历容器。 _list_iterator是链表迭…

Pikachu–XXE漏洞

Pikachu–XXE漏洞 一、XML基础概念 XML文档结构由XML声明&#xff0c;DTD(文档类型定义)&#xff0c;文档元素三部分构成&#xff01; #XML是可扩展标记语言(Extensible Markup Language),是设计用来进行数据的传输与存储。 #eg: <!--XML声明--><!--指明XML文档的版…

matlab-simulink

1、信号到对象解析指示符 代表的意义是&#xff1a;信号名称必须解析为信号对象 2、input inport 双击空白区域输入模块名字&#xff0c;自动联想显示相关模块 没看出太大的差别 3、Stateflow 双击空白区域输入stateflow、或者chart或者常用库里面去查找 4、离散时间积分…

简单几个步骤完成 Oracle 到金仓数据库(KingbaseES)的迁移目标

作为国产数据库的领军选手&#xff0c;金仓数据库&#xff08;KingbaseES&#xff09;凭借其成熟的技术架构和广泛的市场覆盖&#xff0c;在国内众多领域中扮演着至关重要的角色。无论是国家电网、金融行业&#xff0c;还是铁路、医疗等关键领域&#xff0c;金仓数据库都以其卓…

网络安全概论——网络安全基础

一、网络安全引言 信息安全的四个属性&#xff08;信息安全的基本目标 &#xff09; 保密性:信息不会被泄露给非授权用户完整性&#xff1a;保证数据的一致性可用性&#xff1a;合法用户不会被拒绝服务合法使用&#xff1a;不会被非授权用户或以非授权的方式使用 二、网络安全…

数据结构-链式二叉树

文章目录 一、链式二叉树1.1 链式二叉树的创建1.2 根、左子树、右子树1.3 二叉树的前中后序遍历1.3.1前(先)序遍历1.3.2中序遍历1.3.3后序遍历 1.4 二叉树的节点个数1.5 二叉树的叶子结点个数1.6 第K层节点个数1.7 二叉树的高度1.8 查找指定的值(val)1.9 二叉树的销毁 二、层序…

SpringCloud系列教程:微服务的未来(二十三)SpringAMQP快速入门、Work Queues、Fanout交换机

前言 Spring AMQP是Spring框架中用于与消息中间件&#xff08;如RabbitMQ&#xff09;进行交互的一个项目&#xff0c;它简化了消息发送、接收以及消息处理的过程。通过Spring AMQP&#xff0c;开发者可以快速实现基于RabbitMQ的消息传递系统。本文将介绍Spring AMQP的快速入门…

单片机简介

一、单片机简介 电脑和单片机性能对比 二、单片机发展历程 三、CISC VS RISC