萍聚社区-德国热线-德国实用信息网

 找回密码
 注册

微信登录

微信扫一扫,快速登录

萍聚头条

查看: 896|回复: 0

1-1-16-2-4 JDK1.1 中 的 编 码 问 题

[复制链接]
发表于 2003-5-11 23:34 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册 微信登录

x
发信人: cczhuang (火警电话119), 信区: Java
标  题: JDK1.1 中 的 编 码 问 题
发信站: BBS 水木清华站 (Tue Jul 28 14:11:43 1998)

──谈Java 中GB 码 与Unicode 码 的 转 换 JDK1.1 中 的 编 码 问 题

──谈Java 中GB 码 与Unicode 码 的 转 换 <图片>


------------------------------------------------------------------------




JDK1.1 中 的 编 码 问 题

──谈Java 中GB 码 与Unicode 码 的 转 换

徐 绿 兵
电 子 部 信 息 化 工 程 总 体 研 究 中 心
地 址: 北 京9716 信 箱105 分 箱 100101
E-mail: xlb@hotmail.com

------------------------------------------------------------------------




一、Java 引 进Unicode 带 来 的 问 题

牋牋牋牋 Java 从 诞 生 之 日 起, 就 考 虑 了 国 际 化 问 题,char 数 据 类 型
为16 位 就 是 明 证。Java 的char 类 型 是 为 存 放Unicode 码 设 计 的, 但
JDK1.0 中 只 是 引 进 了Unicode 这 个 概 念, 并 没 有 对Unicode 全 面 支 持,
以 至 于Java 程 序 员
觉 得Java 中 的char 类 型 与 C 语 言 中8 位 的char 没 有 什 么 不 同, 只 是
浪 费 空 间 而 已。

牋牋牋牋 JDK1.1 是Java 对 国 际 化 全 面 支 持 的 开 始。JDK1.1 为 支 持
Unicode 而 改 动 或 增 加 了 很 多 类: 对I/O 类 库 做 了 较 大 的 改 动, 除
了 原 来 基 于 字 节 的 流(stream) 库 外, 增 加 了 基 于 字 符 的 流 库(
Reader 和Writer 系 列); 增
加 了Unicode 与 各 种 编 码 的 转 换 类, 如 与GB2312 的 转 换。 这 样Java 实
现 了 内 部 编 码(native encoding) 和Unicode 的 统 一。

牋牋牋牋 如 果Java 程 序 仅 仅 用 于 处 理 英 文, 那 么Java 的Unicode 的 内
部 统 一 对 原 来 用 JDK1.0 所 编 的 程 序 可 以 说 没 有 什 么 影 响。 因 为
Unicode 码 是ASCII 码 的 一 个 超 集。 而 对 用 于 处 理 汉 字 的Java 程 序 的
影 响 是 很 大 的。
如 下 面 的 一 个 程 序 在 中 文Windows95 环 境 下 分 别 用JDK1.0 和JDK1.1 编
译 执 行 的 结 果 是 不 同 的( 以 下 所 有 程 序 都 是 针 对 中 文
Windows95/NT 的):


Test1.java 源 程 序:
public class Test1{
    final static String s = " 汉 字";
    public static void main(String args[]){
        System.out.println("Length of "+s+" is "+s.length());
    }
}



牋牋牋牋 用JDK1.0 编 译 执 行 的 结 果 是:


牋牋牋牋 用JDK1.1 编 译 执 行 的 结 果 是:

牋牋牋牋 Length of 汉 字 is 2

牋牋牋牋 而 该 程 序 用JDK1.0 编 译 再 用JDK1.1 执 行 或 反 过 来 则 汉 字 的
显 示 是 难 以 预 料 的。

牋牋牋牋 再 看 一 个 例 子, 预 先 编 辑 一 个 数 据 文 件, 包 含“ 汉 字”
两 个 字, 取 名 叫 Test.dat。Test2.java 的 作 用 是 把 数 据 从 文 件 中 读
出 来, 然 后 打 印 在 屏 幕 上:


Test2 源 程 序:
import java.io.*;
public class Test2{
    public static void main(String args[]){
        try{
            FileInputStream fis = new FileInputStream("Test.dat");
            int len = fis.available();
            byte[] b = new byte[len];
            String s = new String(b, 0);
            System.out.println(s);
            fis.close();
        }catch(IOException e){
        }
    }
}



牋牋牋牋 这 个 程 序 在JDK1.0 下 编 译 运 行 是 可 以 正 确 显 示“ 汉 字” 两
个 字 的。 但 在JDK1.1 下 编 译 会 出 现“-deprecation” 的 警 告, 运 行 结
果 则 是“?? ×?”, 已 经 面 目 全 非 了。

二、 分 析

牋牋牋牋 Test1 和Test2 在 不 同 的JDK 下 会 有 不 同 的 结 果 正 是JDK1.1 引
进 了Unicode 造 成 的。 在Test1.java 中, 同 样 是 字 符 串“ 汉 字”, 它 的
内 码 共4 个 字 节, 用JDK1.0 编 译 后 变 成String 对 象s 时 只 是 把 每 个 字
节 用 一 个Java
的char 存 放,char 的 高8 位 为0, 所 以 长 度 显 示 为4; 而 用JDK1.1 编 译
后 变 成String 对 象s 时 是 分 别 把 每 个 汉 字 转 成 了 对 应 的 Unicode 码

牋牋牋牋 但 为 什 么 一 个s 是4 个char, 而 另 一 个 是2 个char 且 是Unicode,
却 都 能 在 屏 幕 上 正 确 地 显 示 出“ 汉 字” 两 个 字 呢 ?

牋牋牋牋 由 于JDK1.0 只 是 把 汉 字 内 码 的 单 字 节 扩 展 为 双 字 节, 本
质 上 并 没 有 变, 所 以 汉 字 能 正 确 显 示 是 不 难 理 解 的; 而 在
JDK1.1 下 字 符 串 是Unicode, 它 向 屏 幕 输 出 时 又 做 了 从Unicode 向 本
地 操 作 系 统 编 码( 在
我 们 的 例 子 中 就 是GB 码) 的 转 换, 于 是 仍 能 打 印 出 正 确 的 字。
事 实 上, 即 使 是 英 文 字 符 的 显 示, 这 种 字 符 与Unicode 的 相 互 转
换 仍 然 存 在, 只 是 由 于 它 们 的 对 应 关 系 简 单( 只 是 字 节 数 的 扩
展 或 缩 减), 我
们 不 易 察 觉 罢 了。JDK1.1 做 这 种 转 换 的 目 的 就 是 使 世 界 上 所 有
的 平 台 在Java 虚 拟 机 中 统 一 为 一 种 码 — —Unicode 码。

牋牋牋牋 上 一 段 已 经 说 过JDK1.1 在 显 示 时 会 做 从Unicode 到 本 地 编 码
的 转 换, 因 此 用JDK1.1 执 行Test2 时,System.out.println(s) 语 句 的 执 行
同 样 有 从Unicode 到GB 码 的 转 换。 但String s = new String(b, 0) 语 句 只
是 扩 展 了 字
节, 因 此s 中 仍 可 以 认 为 是GB 码。 而JDK1.1 却 把s 当 作Unicode 字 符 串
看 待, 并 机 械 地 对s 做 了 从Unicode 码 到GB 码 转 换, 这 一 转 换 导 致
了 最 终 结 果 中 出 现 了 很 多“?”( 这 是 在 转 换 过 程 中 未 发 现 相 应
编 码 所 用 的 替
换 符 号)。 下 面 的 改 进 程 序 可 以 在JDK1.1 下 正 确 显 示Test2.dat 的 内
容( 说 明 见 注 释)。


import java.io.*;
public class Test3{
    public static void main(String args[]){
        try{
            FileInputStream fis = new FileInputStream("Test.dat");
            int len = fis.available();
            byte[] b = new byte[len];
            fis.read(b);
            String s = new String(b);// 做 了 从GB 到Unicode 的 转 换
            System.out.println(s);   // 做 了 从Unicode 到GB 的 转 换
            fis.close();
        }catch(IOException e){
        }
    }
}




三、 用JDK1.1 开 发 汉 字 处 理 应 用 程 序 应 注 意 的 问 题

牋牋牋牋 如 果 仅 仅 把 汉 字 用 作 显 示 提 示 信 息, 并 不 需 要 关 心Java
虚 拟 机(JVM) 对 各 种 编 码 间 的 相 互 转 换。 但 如 果 汉 字 是 处 理 的 对
象, 或 者 提 示 信 息 用 汉 字 是 从 文 件 中 获 得 的, 那 就 要 注 意 用
合 适 的 类 或 方
法 了。 以 下 两 个 原 则 可 供 参 考:

牋牋牋牋 1、JVM 内 部 统 一 用Unicode 码。 如 果 这 样, 那 么 所 有 与I/O 打
交 道 的 类 都 应 该 用 基 于 字 符 的 类(Reader/Writer 系 列), 这 可 以 使
Unicode 与 本 地 编 码 的 转 换 由JVM 自 动 进 行。 如 Test3 中 读 文 件 内 容
仍 用 了 基 于 字
节 的 流 类FileInputStream, 而 从 字 节 转 换 为 字 符 串 对 象 s 时 不 用 不
能 转 换 成Unicode 的 构 造 方 法String(b, 0), 而 用 了 能 转 换 成Unicode
的 构 造 方 法String(b), 这 需 要 程 序 员 心 中 有 数, 什 么 时 候 用 什 么
方 法。 如 统 一
用 基 于 字 符 的 类 , 程 序 员 就 可 免 去 注 意 这 种 额 外 的 技 术 细 节
。 如 下 面Test4 与Test3 在JDK1.1 下 有 同 样 的 效 果。

import java.io.*;
public class Test4{
    public static void main(String args[]){
        try{
            FileReader fr = new FileReader("Test.dat");// 基 于 字 符 的 流
            char[] c = new char[2];
            fr.read(c);              // 做 了 从GB 到Unicode 的 转 换
            String s = new String(c);
            System.out.println(s);   // 做 了 从Unicode 到GB 的 转 换
            fr.close();
        }catch(IOException e){
        }
    }
}



牋牋牋牋 2 、JVM 内 部 统 一 用GB 码。 这 可 需 要 程 序 员 注 意 采 用 合 适
的 方 法, 程 序 员 必 须 了 解 哪 些 方 法 会 做 转 换, 哪 些 不 做 转 换,
必 要 时 还 要 调 用 合 适 的 方 法 做 额 外 的 转 换, 以 达 到JVM 内 部 是
GB 码 的 统 一。 应
该 说 这 是 一 种 笨 拙 的 方 法。 但 由 于 基 于GB 码 的 程 序 很 多, 在 程
序 移 植 比 较 困 难 时 仍 可 采 用。 下 面 介 绍 如 何 显 式 调 用 方 法 进
行Unicode 与GB 的 转 换:

牋牋牋牋 1)GB 转 换 为Unicode( 主 要 用 于 将 汉 字 显 示 出 来):

旼B 码 汉 字 串 存 放 在 字 节 数 组 中, 要 转 换 成Unicode 字 符 串 可 用
String 类 的String(byte[]) 构 造 方 法。Test3 中 已 经 用 了 这 个 方 法。
旼B 码 汉 字 串 存 放 在String 对 象 中, 转 换 成Unicode 字 符 串, 可 用 下
面 的 程 序 段:

牋牋牋牋 String chinese, unicode;// 存 放 汉 字 串 和 结 果 字 符 串


       :
      try{
          byte[] b =
chinese.getBytes("8859_1");// 把 汉 字 串 看 作 英 文, 无 转 换
          unicode = new String(b, "GB2312");// 或unicode = new String(b);
      }catch(UnsupportedEncodingException e){
      }


牋牋牋牋 上 面 的 方 法 显 式 使 用 了 编 码 的 名 字, 如"8859_1" 和"GB2312"
。 用"8859_1" 是 一 个 小 技 巧, 这 是 为 了 告 诉JVM 字 符 串 对 象chinese
中 存 放 的 是 西 文, 由 于 西 文 与Unicode 的 对 应 关 系 只 是 字 节 扩 展
, 所 以 字 节 数 组b
中 的 内 容 与chinese 中 的 一 样。

牋牋牋牋 JDK1.1 中 的String 类 提 供 了 一 些 需 要 编 码 名 字 的 方 法。 缺
省 情 况 下 为 操 作 系 统 使用 的 编 码。 上 面 的 方 法 是 巧 用 编 码 名 字
的 一 例。

牋牋牋牋 2)Unicode 转 换 为GB( 主 要 用 于 汉 字 处 理):

牋牋牋牋 如unicode 为 一String 对 象, 取 出 汉 字 可 以 用 下 面 的 方 法:


         byte[] b = unicode.getBytes("GB2312");// 或b =
unicode.getBytes();
      理 由 同 上。




四、 结 束 语

牋牋牋牋 用JDK1.1 重 新 编 译 原 来 在JDK1.0 下 书 写 的Java 程 序 有 时 会 出
现“deprecation” 的 警 告 信 息, 出 现 这 类 警 告 的 方 法 在JDK1.1 的API
文 档 中 会 标 出“deprecated”, 即 不 赞 成 使 用 的 方 法。deprecation 警
告 一 类 是 与 新
的 包java.awt 有 关, 另 一 类 与 编 码 转 换 有 关。 使 用 deprecated 方 法
可 以 不 受 编 码 转 换 的 困 扰, 但 编 译 警 告 总 不 是 令 人 愉 快 的。




------------------------------------------------------------------------
中国计算机世界出版服务公司版权所有





四、 结 束 语

牋牋牋牋 用JDK1.1 重 新 编 译 原 来 在JDK1.0 下 书 写 的Java 程 序 有 时 会 出
现“deprecation” 的 警 告 信 息, 出 现 这 类 警 告 的 方 法 在JDK1.1 的API
文 档 中 会 标 出“deprecated”, 即 不 赞 成 使 用 的 方 法。deprecation 警
告 一 类 是 与 新
的 包java.awt 有 关, 另 一 类 与 编 码 转 换 有 关。 使 用 deprecated 方 法
可 以 不 受 编 码 转 换 的 困 扰, 但 编 译 警 告 总 不 是 令 人 愉 快 的。




------------------------------------------------------------------------
中国计算机世界出版服务公司版权所有





--
※ 来源:·BBS 水木清华站 bbs.net.tsinghua.edu.cn·[FROM: 162.105.160.148]
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
您需要登录后才可以回帖 登录 | 注册 微信登录

本版积分规则

手机版|Archiver|AGB|Impressum|Datenschutzerklärung|萍聚社区-德国热线-德国实用信息网 |网站地图

GMT+2, 2024-6-14 20:16 , Processed in 0.056340 second(s), 16 queries , MemCached On.

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表