一主题关于JAVA的中文问题
JAVA的中文问题比较突出主要表现在控制面板输出JSP页面输出和数据库访问上本文尽量避开字体问题而只谈编码通过本文你可以了解JAVA中文问题的由来问题的解决方法其中提了一下用JDBC访问数据库的方法
二问题描述
)在中文W中文窗口编译和运行用的是国际版的JDK连接的是中文W下的Cp编码的SQL SERVER数据库
J:\exercise\demo\encode\HelloWorld>make
Created by XCompiler PhiloSoft All Rights Reserved
Wed May :: CST
J:\exercise\demo\encode\HelloWorld>run
Created by XRunner PhiloSoft All Rights Reserved
Wed May :: CST
中文
[B@bcb
[B@bb
[B@b
中文
中文
????
中文
中文
????
??
??
??
)如果在中文W的西文窗口(编码为)下编译用JAVA运行则由于无字体而无法正常显示如果象上面一样在中文W的中文窗口运行输出为
J:\exercise\demo\encode\HelloWorld>run
Created by XRunner PhiloSoft All Rights Reserved
Wed May :: CST
????
[B@bcba
[B@bba
[B@ba
????
????
????
????
????
????
中文
中文
????
三)分析
)出现有乱码(也就是?)由于只出现?而没出现小方框说明只是编码有问题而不是字体问题 在编码中如果从一种字符集转换到别一种字符集比较典型的是从GB转换到ISO_(即ASCII)那么很多汉字(半个汉字)是无法映射到西文字符中去的在这种情形下系统就把这些字符用?代替同样也存在小字符集无法到大字符集的情况具体原因这里就不详谈了
)出现了中文环境编译中文环境运行时汉字显示有正确也有不正确的地方同样在西文环境下编译在中文环境下运行时也出现类似情况这是由于自动(默认)或手工(也就new String(bytes[encode])和bytes getBytes([encode]))转码的结果
)在JAVA源文件>JAVAC>Class>Java>getBytes()>new String()>显示的过程中每一步都有编码的转换过程这个过程总是存在的只是有的时候用默认的参数进行下面我们一步一步分析为什么出现上面的情形
)这里是源代码
HelloWorldjava:
public class HelloWorld
{
public static void main(String[] argv){
try{
Systemoutprintln(中文);//
Systemoutprintln(中文getBytes());//
Systemoutprintln(中文getBytes(GB));//
Systemoutprintln(中文getBytes(ISO_));//
Systemoutprintln(new String(中文getBytes()));//
Systemoutprintln(new String(中文getBytes()GB));//
Systemoutprintln(new String(中文getBytes()ISO_));//
Systemoutprintln(new String(中文getBytes(GB)));//
Systemoutprintln(new String(中文getBytes(GB)GB));//
Systemoutprintln(new
String(中文getBytes(GB)ISO_));//
Systemoutprintln(new String(中文getBytes(ISO_)));//
Systemoutprintln(new
String(中文getBytes(ISO_)GB));//
Systemoutprintln(new
String(中文getBytes(ISO_)ISO_));//
}
catch(Exception e){
eprintStackTrace();
}
}
}
为了方便起见在每个转换的后面加了操作序号分别为
)需要说明的是JAVAC是以系统默认编码读入源文件然后按UNICODE进行编码的在JAVA运行的时候JAVA也是采用UNICODE编码的并且默认输入和输出的都是操作系统的默认编码也就是说在new String(bytes[encode])中系统认为输入的是编码为encode的字节流换句话说如果按encode来翻译bytes才能得到正确的结果这个结果最后要在JAVA中保存它还是要从这个encode转换成Unicode也就是说有bytes>encode字符>Unicode字符的转换而在StringgetBytes([encode])中系统要做一个Unicode字符>encode字符>bytes的转换
在这个例子中除那个英文窗口编码的时候除外其实情形下默认编码都是GBK(在本例中我们暂且把GBK和GB等同看待)
)由于在未指明在上面的两个用代码实现的转换中如果未指定encode系统将采用默认的编码(这里为GBK)我们认为上面的和是一样的和和也是一样的所以我们在讨论中将只讨论其中的只是用于测试不在我们的讨论范围之内
)下面我们来跟蹤程序中的中字的转换历程我们先说在中文窗口下作的编译和运行过程注意在下面的字母下标中我有意识地使用了一些数字以表示相同相异还是相关)我们先以上面的个代码段中的的代码为例
步骤 内容 地点 说明
C HelloWorldjava C泛指一个GBK字符
U JAVAC读取 U泛指一个Unicode字符
C getBytes()第一步 JAVA先和操作系统交流
BB getBytes()第二步 然后返回字节数组
C new String()第一步 JAVA先和操作系统交流
U new String()第二步 然后返回字符
C println(String) 能显示中字内容和原来的相同
)然后再以代码段为例我们注意到只是
步骤 内容 地点 说明
C HelloWorldjava C泛指一个GBK字符
U JAVAC读取 U泛指一个Unicode字符
C getBytes()第一步 JAVA先和操作系统交流
BB getBytes()第二步 然后返回字节数组
CC new String()第一步 JAVA先和操作系统交流这时解析错误
UU new String()第二步 然后返回字符
CC println(String) 由于中字给分成了两半在ISO_中刚好也没有字符
能映射上所以显示为??在上面的示例中
中文两个字就显示为????
)在完全中文模式下的其它情形类似我就不多说了
)我们接着看为什么在西文DOS窗口下编译出来的类在中文窗口下也出现类似情形特别是为什么居然有的情形下还能正确显示汉字
)我们还是先以代码段为例
步骤 内容 地点 说明
CC HelloWorldjava CC分别泛指一个ISO_字符中字被拆开
UU JAVAC读取 UU泛指一个Unicode字符
CC getBytes()第一步 JAVA先和操作系统交流这时解析错误
BBBB getBytes()第二步 然后返回字节数组
CC new String()第一步 JAVA先和操作系统交流
UU new String()第二步 然后返回字符
CC println(String) 虽然同是两个字符但已不是最初的两个ISO_字
符而是两个BGK字符中显示成了??
而中文就显示成了????
)下面我们以代码段为例因为它能正确显示汉字
步骤 内容 地点 说明
CC HelloWorldjava CC分别泛指一个ISO_字符中字被拆开
UU JAVAC读取 UU泛指一个Unicode字符
CC getBytes()第一步 JAVA先和操作系统交流(注意还是正确的哦!)
BB getBytes()第二步 然后返回字节数组(这是很关键的一步!)
C new String()第一步 JAVA先和操作系统交流(这是更关键的一步JAVA已经知道BB要解析成一个汉字!)
U new String()第二步 然后返回字符(真是一个项两!U包含了UU的信息)
C println(String) 这就原来的中字很委屈被JAVAC冤枉了一回不过被程序员拨乱反正了一下!当然中文两个字都能正确显示了!
)那为什么有的时候用JDBC的
new String(RecordsetgetBytes(int)[encode])
RecordsetgetSting(int)
RecordsetsetBytes(StringgetBytes([encode]))
和
RecordsetsetString(String)
的时候会出现乱码了呢?
其实问题就出现在编写JDBC的的也考虑了编码问题它从数据库读取数据后可能自作主张做了一个从GB(默认编码)到Unicode的转换我的这个WebLogic For SQL Server的JDBC Driver就是这样的当我读字串的时候发出读到的不是正确的汉字可恨的是我却可以直接写汉字字串这让人多少有点难以接受!
也就是说我们不得不在读或写的时候进行转码尽管这个转码有的时候不是那么明显这是因为我们使用了默认的编码进行转码JDBC Driver