|
本帖最后由 locust_j 于 2009-8-15 12:17 编辑
JAVA的一些东东
java中文问题详解 预备知识: 1.字节和unicode Java内核是unicode的,就连class文件也是,但是很多媒体,包括文件/流的保存方式 是使用字节流的。 因此Java要对这些字节流经行转化。char是unicode的,而byte是字节. Java中byte/char互转的函数在sun.io的包中间有。其中ByteToCharConverter类是中调度, 可以用来告诉你,你用的Convertor。其中两个很常用的静态函数是 public static ByteToCharConverter getDefault() ; public static ByteToCharConverter getConverter(String encoding); 假如你不指定converter,则系统会自动使用当前的Encoding,GB平台上用GBK,EN平台上用 8859_1 我们来就一个简单的例子: "你"的gb码是:0xC4E3 ,unicode是0x4F60 你用: --encoding="gb2312"; --byte b[]={(byte)"u00c4",(byte)"u00E3"}; --convertor=ByteToCharConverter.getConverter(encoding); --char [] c=converter.convertAll(b); --for(int i=0;i --{ -- System.out.println(Integer.toHexString(c)); --} --打印出来是0x4F60 --但是假如使用8859_1的编码,打印出来是 --0x00C4,0x00E3 ----例1 反过来: --encoding="gb2312"; char c[]={"u4F60"}; convertor=ByteToCharConverter.getConverter(encoding); --byte [] b=converter.convertAll(c); --for(int i=0;i --{ -- System.out.println(Integer.toHexString(b)); --} --打印出来是:0xC4,0xE3 ----例2 --假如用8859_1就是0x3F,?号,表示无法转化 -- 很多中文问题就是从这两个最简单的类派生出来的。而却有很多类 不直接支持把Encoding输入,这给我们带来诸多不便。很多程序难得用encoding 了,直接用default的encoding,这就给我们移植带来了很多困难 -- 2.UTF-8 --UTF-8是和Unicode一一对应的,其实现很简单 -- -- 7位的Unicode: 0 _ _ _ _ _ _ _ --11位的Unicode: 1 1 0 _ _ _ _ _ 1 0 _ _ _ _ _ _ --16位的Unicode: 1 1 1 0 _ _ _ _ 1 0 _ _ _ _ _ _ 1 0 _ _ _ _ _ _ --21位的Unicode: 1 1 1 1 0 _ _ _ 1 0 _ _ _ _ _ _ 1 0 _ _ _ _ _ _ 1 0 _ _ _ _ _ _ --大多数情况是只使用到16位以下的Unicode: --"你"的gb码是:0xC4E3 ,unicode是0x4F60 --我们还是用上面的例子 -- --例1:0xC4E3的二进制: -- -- 1 1 0 0 0 1 0 0 1 1 1 0 0 0 1 1 -- -- 由于只有两位我们按照两位的编码来排,但是我们发现这行不通, -- -- 因为第7位不是0因此,返回"?" -- -- -- --例2:0x4F60的二进制: -- -- 0 1 0 0 1 1 1 1 0 1 1 0 0 0 0 0 -- -- 我们用UTF-8补齐,变成: -- -- 11100100 10111101 10100000 -- -- E4--BD-- A0 -- -- 于是返回0xE4,0xBD,0xA0 -- -- 3.String和byte[] --String其实核心是char[],然而要把byte转化成String,必须经过编码。 --String.length()其实就是char数组的长度,假如使用不同的编码,很可 --能会错分,造成散字和乱码。 --例: ----byte [] b={(byte)"u00c4",(byte)"u00e3"}; ----String str=new String(b,encoding); ---- ----假如encoding=8859_1,会有两个字,但是encoding=gb2312只有一个字 ---- --这个问题在处理分页是经常发生 4.Reader,Writer/InputStream,OutputStream --Reader和Writer核心是char,InputStream和OutputStream核心是byte。 --但是Reader和Writer的主要目的是要把Char读/写InputStream/OutputStream --一个reader的例子: --文件test.txt只有一个"你"字,0xC4,0xE3-- --String encoding=; --InputStreamReader reader=new InputStreamReader( ----new FileInputStream("text.txt"),encoding); --char []c=new char[10]; --int length=reader.read(c); --for(int i=0;i ----System.out.println(c); --假如encoding是gb2312,则只有一个字符,假如encoding=8859_1,则有两个字符 -------- -- -- ---- 2.我们要对Java的编译器有所了解: --javac -encoding 我们经常没有用到ENCODING这个参数。其实Encoding这个参数对于跨平台的操作是很重要的。 假如没有指定Encoding,则按照系统的默认Encoding,gb平台上是gb2312,英文平台上是 ISO8859_1。 --Java的编译器实际上是调用sun.tools.javac.Main的类,对文件进行编译,这个类 -- 有compile函数中间有一个encoding的变量,-encoding的参数其实直接传给encoding变量。 编译器就是根据这个变量来读取java文件的,然后把用UTF-8形式编译成class文件。 一个例子: --public void test() --{ ----String str="你"; ----FileWriter write=new FileWriter("test.txt"); ----write.write(str); ----write.close(); --} ----例3 --假如用gb2312编译,你会找到E4 BD A0的字段 -- --假如用8859_1编译, --00C4 00E3的二进制: --00000000 11000100 00000000 11100011-- --因为每个字符都大于7位,因此用11位编码: --11000001 10000100 11000011 10100011 --C1-- 84-- C3-- A3 --你会找到C1 84 C3 A3 -- 但是我们往往忽略掉这个参数,因此这样往往会有跨平台的问题: -- 例3在中文平台上编译,生成ZhClass -- 例3在英文平台上编译,输出EnClass --1. ZhClass在中文平台上执行OK,但是在英文平台上不行 --2. EnClass在英文平台上执行OK,但是在中文平台上不行 原因: --1.在中文平台上编译后,其实str在运行态的char[]是0x4F60, ---- --在中文平台上运行,FileWriter的缺省编码是gb2312,因此 --CharToByteConverter会自动用调用gb2312的converter,把str转化 --成byte输入到FileOutputStream中,于是0xC4,0xE3放进了文件。 --但是假如是在英文平台下,CharToByteConverter的缺省值是8859_1, --FileWriter会自动调用8859_1去转化str,但是他无法解释,因此他会 --输出"?" ---- --2. 在英文平台上编译后,其实str在运行态的char[]是0x00C4 0x00E3, ---- --在中文平台上运行,中文无法识别,因此会出现?? -- 在英文平台上,0x00C4-->0xC4,0x00E3->0xE3,因此0xC4,0xE3被放进了 --文件 ---- 1.对于jsp正文的解释: --Tomcat首先看一下你的叶面中有没有" http://localhost/test/test.jsp?value=你 结果:你好你 但这种方法局限性较大,比如对上传的文章分段,这样的做法是死定的,最好的 解决方案是用这种方案: 你好 必读好文,但解决方案不敢恭维 Java常见问题集锦 问: 如何设置Java 2(JDK1.2)的环境变量? 答: Java 2安装后,需要设置PATH和JAVA_HOME环境变量.与JDK1.1不同的是:设置好JAVA_HOME环境变 量后,JVM将自动搜索系统类库以及用户的当前路径. Java 2环境变量的设置如下例所示: Solaris平台: setenv JAVA_HOME Java2的安装路径 setenv PATH $JAVA_HOME/bin:${PATH} Windows平台: set JAVA_HOME=Java2的安装路径 set PATH=$JAVA_HOMEbin;%PATH% 问: 哪些Java集成开发工具支持Java 2? 答: 目前流行的Java集成开发环境,如Inprise的JBuilder,Symantec的Visual Cafe, Sybase的 PowerJ,都支持Java 2. 问: 假如在Netscape或IE浏览器中运行Java applet时出现了错误,如何确定错误范围? 答: 当java applet在浏览器中运行时,使用的是浏览器本身的缺省JVM.而不同浏览器对JDK的支持程 度也不尽相同. 因此,在Netscape或IE浏览器中运行Java applet出现了错误,建议使用JDK提供的工具 appletviewer或Sun公司的Hotjava浏览器来测试该applet,以确定错误的产生是与浏览器相关. 假如applet在appletviewer或Hotjava中运行一切正常,则错误的产生是由于浏览 器不完全兼容JDK而 引起的. 此时,解决方法可以是使用Hotjava浏览器或者安装 Sun公司的Java Plugin. 假如applet在Hotjava浏览器或appletviewer中运行即发生错误,则应当根据错误 提示检查applet程 序. 问: 当用JDBC向数据库中插入数据或从数据库中提取数据时,为何有时中文字符会显示为乱码? 答: 这个问题的实现通常与各个JDBC driver的实现有关. 目前大多数JDBC driver采用本地编码格式 来传输中文字符,例如中文字符"0x4175"会被转成"0x41"和"0x75"进行传输. 因此我们需要对JDBC driver 返回的字符以及要发给JDBC driver的字符进行转换. 当用JDBC driver向数据库中插入数据时,需要先将Unicode转成native code; 当 JDBC driver从数据 库中查询数据时,则需要将native code转换成Unicode. 下面给出了这两种转换的实现: String native2Unicode(String s) { if (s == null s.length() == 0) { return null; } byte[] buffer = new byte[s.length()]; for (int i = 0; i s.length(); i++) { if (s.charAt(i)>= 0x100) { c = s.charAt(i); byte []buf = (""+c).getBytes(); buffer[j++] = (char)buf[0]; buffer[j++] = (char)buf[1]; } else { buffer[j++] = s.charAt(i); } } return new String(buffer, 0, j); } 除使用以上两个方法之外,有些JDBC driver假如对jdbc driver Manager设置了正确 的字符集属性, 以上2个方法就不需要了. 问: 当用Servlet来处理http请求并产生返回的Html页面时,如何使HTML页面中的中文字符能够正常显示? 答: javax.servlet.http.HttpResponse类用于产生返回页面.通过HttpResponse定义的方法 getOutputStream()可以获得ServletOutputStream的实例,这样用户就可以利用 ServletOutputStream.write方法向输出流中写入返回页面的内容. 但是ServletOutputStream使用的是缺 省的编码方式,假如要使返回页面中的中文字 符能够正常显示,最好显示地指定所用的字符编码方式. 通 常需要构造一个 OutputStreamWriter , 例程如下: public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html"); ServletOutputStream out = res.getOutputStream(); OutputStreamWriter ow = new OutputStreamWriter(out,"GB2312"); ow.write("这是测试"); ow.flush(); ow.close(); } 问: 如何设置Java WebServer的CLASSPATH,以包含用户的class文件? 答: 有两种方法可以设置Java WebServer的CLASSPATH环境变量,以使用户编写的Servlet能够调用用户的 class文件. 将用户的class文件放到 JavaWebServer_Dir/classes目录下,在Java WebServer 启动时,classes目 录被自动加入到CLASSPATH环境变量中了. 修改httpd.nojre文件,将用户class文件所在的路径名加到CLASSPATH环境变量中. 问: 为什么在Windows平台上用Naming.lookup来获取远程RMI对象时会很慢? 答: 机器的网络设置不正确很可能会引起该问题的发生. RMI使用了Java网络类,非凡是java.net.InetAddress类,它将查询TCP/IP的主机名, 包括IP地址到主 机名的映射和主机名到IP地址的映射.在Windows平台,这种查询功能 是由本地的Windows Socket库来实现 的. 因此延时是发生在Windows库中,而非RMI中. 假如你的机器设置成使用DNS,问题通常是DNS服务器查不到主机名,你所发现的延时 是DNS查询的延时 . 请尝试将RMI通信中涉及到的所有主机名/IP地址加到本地文件 winntsystem32driversetchosts或 windowshosts中. 格式如下: IP地址 主机名 如此设置应当可以明显地减少查询所花的时间. 问: 编写Java application时,如何设置proxy的信息,以便访问外部网站? 答: 若在java application中访问外部网站,首先应设置proxy信息,样例代码如下: import java.util.properties; ..... Properties sys = System.getProperties(); sys.put("proxySet","true"); sys.put("proxyHost","myHTTP.proxyserver.com"); sys.put("proxyPort","80"); System.setProperties(sys); u = new URL(website); connect = (HttpURLConnection)u.openConnection(); ..... 问: Swing组件JList的列表数据修改了,如何通知JList改变显示? 答: JList组件有一个单独的显示模式ListModel来表示JList的显示数据. JList创建以后,JList数据元素的值及数据元素的数量可以动态地改变. JList在它的数据模式ListModel中观察数据的改变.因此,一个ListModel 的正确实现应当在每次数据 发生改变时,通知事件的监听者. 当使用构造函数JList(Object[])创建一个JList的实例时,系统将自动 创建一个DefaultListModel的 实例来存储JList的显示数据, 可以调用 DefaultListModel中定义的简便方法来动态地修改JList的数据, 如 removeElementAt(index),addElement(Object)等. DefaultListModel 在修改数据的同时,将通知 JList关于数据的改变. 问: 在Java applet中如何实现一个模式对话框? 答: 在Java applet中实现模式对话框的要害就是在创建一个对话框的时候 要为该对话框指定一个正确的 父窗口.因为Applet是Panel类的子类,不 可以作为对话框的父窗口,所以首先要获得applet所在的窗口,作 为模式 对话框的父窗口. 样例代码如下: ..... Dialog d = new Dialog( getParentWindow(comp),title); // comp为applet上的任意一个组件 .... public void getParentWindow(Component compOnApplet,String title){ Container c = compOnApplet.getParent(); while (c != null) { if (c instanceof Frame) return (Frame) c; c = c.getParent(); } return null; } 问: 在Java applet中如何显示另外一个HTML页面? 答: 通过java.applet.Applet.getAppletContext()方法可以获得与该applet相关的AppletContext, AppletContext.showDocument(URL)方法就可以使applet所在的浏览器显示另外一个网页. 问: 用JDK实现的签名applet,可否在Netscape或IE中运行? 答: 用JDK实现的签名applet,不可以在Netscape或IE中运行,但是可以在Hotjava浏览器中运行. 不同的浏览器提供了不同的签名applet机制,如Netscape提供了zigbert工具和 Capability API, 而 IE则需要使用CAB文件. 但是,无论是Netscape工具产生的 签名applet,还是用IE产生的签名applet,都不 可以在其它的浏览器中运行. 假如要使JDK产生的签名applet能够在Netscape或IE中运行,解决方法是在 Netscape或IE中安装Java Plugin,则用JDK实现的签名applet就可以在这两种 浏览器中运行. 问: 用JNI技术可以从Java应用中调用C程序库,但是如何使该C程序库可以调用另外的C程序库? 答: 假如一个被Java调用的C程序库C1仍需要调用另外一个C程序库C2,那么在编译C1的时候应当联接程序 库C2,步骤如下(Solaris平台): 编写调用C库的Java文件,并编译. javac java文件名 产生C程序头文件 javah -jni java文 初学Java注意什么 Java总有它的千般好处使你选择它,但这些随便翻翻书或在网上逛一圈就能找到答案。在本文中,笔者把 自己学习Java的一些切身体会和过程写出来,供初学者做个参考。 我在学习Java的过程中主要围绕以下几个方面来学习: 1.时刻提醒自己Java是一种OOP语言工具,而不仅仅是编码,只有这样才能总体把握和运用Java。 2.在学习的过程中,最好能够了解Java的底层机制,而不是仅仅停留在表层,不是抄书上的例子运 行出结果就可以。要注重,即便对一个简单的例子也要有耐心去琢磨、调试、改动。 3.在学习的过程中一定要动手做、写代码,而不是抱一本书看看就行。很多东西和体会必须自己动 手才能真正属于自己,最好能参与一些实际的项目。 4.在学到一定阶段后,你开始希望用学过的东西做些什么。这时的你应该开始学习一些更多、更复 杂的知识,比如J2EE平台的构建、EJB的开发等。对于这一部分,我建议最好找一本较薄的书先了解一个 大概,心里有个总体的熟悉,对更多的技术术语做个初步把握。我认为这个阶段看看《J2EE技术实践》很 不错,它可以让你了解J2EE包含的各种技术和框架,同时提供很多实际的例子来加深对J2EE的整体了解。 学习Java的爱好和决心起了很要害的作用。在有了上述基础后,我便开始一步一步地学习Java。 Java环境的搭建 要运行Java程序,必须安装JDK。JDK是整个Java的核心,其中包括了Java编译器、JVM、大量的Java 工具以及Java基础API。 可以从http://Java.sun.com下载JDK,有1.4版本和1.31版本。我的学习环境中首先,采用的是1.31 版本。 解压安装。然后,进行环境设置。 1.对于Windows平台要进行以下设置: set PATH=YOUR_INSTALL_ DIR\bin; C:\Windows;C:\Windows\Command set classpath=. ;YOUR_INSTALL_DIR\lib\tools.jar 2.对于Linux平台要编辑/etc/profile文件: JAVA_HOME=your_install_dir/JDK/j2sdk CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/td.jar:$JAVA_HOME/jr -e/lib/rt.jar:. PATH=$PATH:$JAVA_HOME/bin eXPort PATH PS1 USER LOGNAME MAIL HOSTNAME HISTSIZE HISTFILESIZE INPUTRC JAVA_HOME CLASSPATH RESIN_HOME 最后,在终端上输入Java看能不能找到这个命令,假如能找到安装就成功了。 下面介绍一下JDK的几个重要的命令: ◆Java执行工具,是启动JVM(虚拟机)并执行class(BYTE CODE)文件的命令; ◆javac 编译器,由.java文件生成.class文件; ◆jar Java压缩打包工具; ◆Javadoc 文档生成器。 最后就是JDK Documentation,这是JDK的联机帮助文档,是最有用和最重要的学习参考文档,应该多 看。 开始写自己的代码 现在环境有了,应该写个简单的代码进行测试了。还是从经典的“hello Word”开始。 1. 先用编辑器写一代码(我用的是Linux的vi): [stone@coremsg work]$ vi Hello.Java public class Hello{ public static void main(String []argc){ System.out.println("Hello Word!"); } } 2. 编译: [stone@coremsg work]$ Javac Hello.Java 3. 执行: [stone@coremsg work]$ Java Hello Hello Word! 成功了!这就是我的第一个Java程序。从那时起我知道已开始走进Java的世界,接下来就靠自己的努 力了。在这个过程中,笔者认为有几点需要注重。 学习一门新的语言,参考书是离不开的。我的建议是开始最好找一本篇幅较短的入门书来学习那些最 简单、最基本的东西,包括学习Java语法等。同时,对一个最简单的程序也应该多去调试,多想想假如改 动一下会出现什么结果?为什么必须那样写?多去想想这些问题然后去操作,会让你有更多的收获。这样 反复地思考是很有用的。此外,在这一阶段还应该多看JDK的联机帮助,尽量多地把握JDK提供的Java基本 类库API。 在有一定基础、能够写一些简单的程序后,可以开始看《Thinking in Java》这本书。它比较完整地 介绍了Java的语法、面向对象的特性、核心类库等。通过这一层次的学习能够加深对Java的理解和底层原 理的运用,同时又可以完整地了解Java的整个体系。在这一阶段,应该重点学习Java的面向对象编程语言 的特性,比如继续、构造器、抽象类、接口、方法的多态、重载、覆盖、Java的异常处理机制等,要对上 述概念有非常清楚的了解。这样做的目的,是要让自己把这些技术应用到实践中进行合理的程序设计(比 如,你会考虑一个类是用抽象还是接口来设计等)。这就要求必须在大量的实践中去应用和学习。这也是 当初很多朋友给我的建议。 学习更多 假如要用Java来完成各种功能更强大的任务,那么就要学习语言以外的更多的东西。 1.Java Web编程 对于Java Web 编程来说,应该而且必须熟悉和把握HTTP协议,可以参考 Stevens的《TCP/IP 详解》 第三卷。Java Servlet技术提供了生成动态Web页面内容的能力,这在你的Java项目中是最基本的功能之 一,所以必须学习。通过这一阶段的学习应该把握Servlet/jsp的Web编程。 2. J2EE的学习 J2EE包含的技术太多了。假如你想坐在桌子旁边抱着一大堆书来学习的话,效果不大的。我建议在开 始这一阶段的学习的时候,可以按以下步骤来做,总的思想是“总体把握,各个击破”。 ◆ 了解J2EE中的技术术语的含义。 我的感觉是J2EE标准中涉及到的各种技术很多,假如一开始就一个一个去学习的话是不现实的,也是 没效果的。我的建议是,先对其中的技术有个大概的了解,比如EJB、JavaIDL、JTA等。可能你不知道怎 么去写一个EJB,但是要知道什么是EJB、它能做什么,当有了这样的概念后,再去有目的地学习它就会快 很多。我还要再重复一句——必须要在实践中动手去做才行。 ◆ 了解J2EE中的设计模式,这样能帮助你对J2EE做个整体把握。 MVC开发模式被证实是有效的处理方法之一。它可以分离数据访问和数据表现。你可以开发一个有伸 缩性的、便于扩展的控制器,来维护整个流程。通过这一层次的学习,当你面对一个项目的时候,应该首 先把握它的总体架构的设计,以及决定采用J2EE标准中的哪些技术。 ◆ 了解一些J2EE平台的典型案列,加深对这一技术的概念和理解。 平时可以多留意这方面,熟悉一些典型案例,分析它为什么要采用那个时间?那样做能达到什么样的 目的?然后联系到自己身边的项目是否可以作为参考。 ◆ 学习J2EE下的各种技术。 在有了前几阶段的学习后,可以自己搭建一个J2EE平台开始具体学习每一种技术。你可以参与公司相 关项目进行学习,也可以自己搭建一个平台进行学习。这时候应该找点相关的书来一步一步学习,没有捷 径可走。假如你不满足于这些,那么还应该更深入地学习UML、设计模式等方面的东西。 |