﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-早餐2块2-文章分类-java基础</title><link>http://www.blogjava.net/formatmyself/category/4446.html</link><description>if(!java.isExist()) boss.fireOut(me);</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 14:23:46 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 14:23:46 GMT</pubDate><ttl>60</ttl><item><title>自己写了一个比较变态的类，测试一下关于类初始化顺序的知识~</title><link>http://www.blogjava.net/formatmyself/articles/30240.html</link><dc:creator>早餐2块2</dc:creator><author>早餐2块2</author><pubDate>Fri, 10 Feb 2006 18:03:00 GMT</pubDate><guid>http://www.blogjava.net/formatmyself/articles/30240.html</guid><wfw:comment>http://www.blogjava.net/formatmyself/comments/30240.html</wfw:comment><comments>http://www.blogjava.net/formatmyself/articles/30240.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/formatmyself/comments/commentRss/30240.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/formatmyself/services/trackbacks/30240.html</trackback:ping><description><![CDATA[public class Outer {<BR>&nbsp;&nbsp;&nbsp; public Outer() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("a");<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; public static void sayOther(String s){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(s);<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; public int say(String s){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(s);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("c");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inner.innerMethed("d");<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; static<BR>&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("e");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inner.innerMethed("f");<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; private int i=say("g");<BR>&nbsp;&nbsp;&nbsp; private static inner t= new inner();<BR>&nbsp;&nbsp;&nbsp; private inner tt=new inner();<BR>&nbsp;&nbsp;&nbsp; private innerOther ttt=new innerOther();<BR>&nbsp;&nbsp;&nbsp; static class inner{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public inner(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("h");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void innerMethed(String s){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(s);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("i");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("j");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; class innerOther{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public innerOther(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("k");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("l");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("m");<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Outer outer = new Outer();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("n");<BR>&nbsp;&nbsp;&nbsp; }<BR>}<BR><BR><BR><BR>答案是：ejfihmcdgihlkan<BR><img src ="http://www.blogjava.net/formatmyself/aggbug/30240.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/formatmyself/" target="_blank">早餐2块2</a> 2006-02-11 02:03 <a href="http://www.blogjava.net/formatmyself/articles/30240.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>String类的equals方法和==方法的比较</title><link>http://www.blogjava.net/formatmyself/articles/27168.html</link><dc:creator>早餐2块2</dc:creator><author>早餐2块2</author><pubDate>Sun, 08 Jan 2006 11:24:00 GMT</pubDate><guid>http://www.blogjava.net/formatmyself/articles/27168.html</guid><wfw:comment>http://www.blogjava.net/formatmyself/comments/27168.html</wfw:comment><comments>http://www.blogjava.net/formatmyself/articles/27168.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/formatmyself/comments/commentRss/27168.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/formatmyself/services/trackbacks/27168.html</trackback:ping><description><![CDATA[<P>先看下面的例子:<BR>01: public class StringExample<BR>02: {<BR>03: public static void main (String args[])<BR>04:&nbsp;&nbsp; {<BR>05: String s0 = "Programming";<BR>06: String s1 = new String ("Programming");<BR>07: String s2 = "Program" + "ming";<BR>08:<BR>09: System.out.println("s0.equals(s1): " + (s0.equals(s1)));<BR>10: System.out.println("s0.equals(s2): " + (s0.equals(s2)));<BR>11: System.out.println("s0 == s1: " + (s0 == s1));<BR>12: System.out.println("s0 == s2: " + (s0 == s2));&nbsp;&nbsp; <BR>13:&nbsp;&nbsp;&nbsp; }}<BR>这个例子包含了3 个String 型变量,其中两个被赋值以常量表达式“Programming”;另一个被赋值以一个新建的值为“Programming”的String 类的实例。使用equals(...)方法和“= =”运算符进行比较产生了下列结果:<BR>s0。equals(s1): true<BR>s0。equals(s2): true<BR>s0 == s1: false<BR>s0 == s2: true</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String.equals()方法比较的是字符串的内容,使用equals(...)方法会对字符串中的所有字符一个接一个地进行比较,如果完全相等那么返回true。 在这种情况下全部字符串都是相同的,所以当字符串s0 与s1 或s2 比较时我们得到的返回值均为true 。运算符“==”比较的是String 实例的引用。在这种情况下很明显s0 和s1 并不是同一个String 实例,但s0 和s2 是同一个。读者也许会问s0 和s2 怎么是同一个对象呢？<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个问题的答案来自于Java语言规范中关于字符串常量String Literals 的章节。本例中“Programming” ,“Program”和“ming”都是字符串常量!!它们在编译期就被确定了当一个字符串由多个字符串常量连接而成时,例如s2 ,它同样在编译期就被确定为一个字符串常量。Java 确保一个字符串常量只有一份拷贝,所以当Programming”和“Program”+“ming”被确定为值相等时,Java 会设置两个变量的引用为同一个常量的引用。在常量池constant pool 中,Java 会跟踪所有的字符串常量。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 常量池指的是在编译期被确定,并被保存在已编译的.class 文件中的一些数据。它包含了关于方法,类,接口等等,当然还有字符串常量的信息。当JVM 装载了这个.class 文件。变量s0 和s2 被确定,JVM 执行了一项名为常量池解析constant pool resolution 的操作。该项操作针对字符串的处理过程包括下列3 个步骤,摘自JVM 规范5。4 节::<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ¹ 如果另一个常量池入口constant pool entry 被标记为CONSTANT_String2 ,并且指出同样的Unicode 字符序列已经被确定,那么这项操作的结果就是为之前的常量<BR>池入口创建的String 实例的引用。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ² 否则,如果intern()方法已经被这个常量池描述的一个包含同样Unicode 字符序列的String 实例调用过了,那么这项操作的结果就是那个相同String 实例的引用。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ³ 否则,一个新的String 实例会被创建它包含了CONSTANT_String 入口描述的Unicode 字符;序列这个String 实例就是该项操作的结果。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 也就是说,当常量池第一次确定一个字符串,在Java 内存栈中就创建一个String 实例。在常量池中,后来的所有针对同样字符串内容的引用,都会得到之前创建的String 实例。当JVM 处理到第6 行时,它创建了字符串常量Programming 的一份拷贝到另一个String 实例中。所以对s0 和s1 的引用的比较结果是false ,因为它们不是同一个对象。这就是为何s0==s1 的操作在某些情况下与s0.equals(s1)不同。s0==s1 比较的是对象引用的值;而s0.equals(s1)实际上执行的是字符串内容的比较。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 存在于.class 文件中的常量池,在运行期被JVM 装载,并且可以扩充。此前提到的intern()方法针对String 实例的这个意图提供服务。当针对一个String 实例调用了intern()方法,intern()方法遵守前面概括的第3 步以外的常量池解析规则:因为实例已经存在,而不需要另外创建一个新的。所以已存在的实例的引用被加入到该常量池。来看看另一个例子:<BR>01: import java.io.*;<BR>02:<BR>03: public class StringExample2<BR>04: {<BR>05: public static void main (String args[])<BR>06:{<BR>07: String sFileName = "test.txt";<BR>08: String s0 = readStringFromFile(sFileName);<BR>09: String s1 = readStringFromFile(sFileName);<BR>10:<BR>11: System.out.println("s0 == s1: " + (s0 == s1));<BR>12: System.out.println("s0.equals(s1): " + (s0.equals(s1)));<BR>13:<BR>14: s0.intern();<BR>15: s1.intern();<BR>16:<BR>17: System.out.println("s0 == s1: " + (s0 == s1));<BR>18: System.out.println("s0 == s1.intern(): " +<BR>19: (s0 == s1.intern()));<BR>20: }<BR>21:<BR>22: private static String readStringFromFile (String sFileName)<BR>23: {<BR>24: //…read string from file…<BR>25: }<BR>26: }<BR>&nbsp;&nbsp;&nbsp;&nbsp; 这个例子没有设置s0 和s1 的值为字符串常量,取而代之的是在运行期它从一个文件中读取字符串,并把值分配给readStringFromFile(...)方法创建的String 实例。从第9 行开始,程序对两个被新创建为具有同样字符值的String 实例进行处理。当你看到从第11 行到12 行的输出结果时,你会再次注意到这两个对象并不是同一个,但它们的内容是相同的。输出结果如下:<BR><BR>s0 == s1: false<BR>s0.equals(s1): true<BR>s0 == s1: false<BR>s0 == s1.intern(): true<BR>第14 行所做的是将String 实例的引用s0 存入常量池。当第15 行被处理时,对s1.intern()方法的调用,会简单地返回引用s0。 这样一来第17 行和18 行的输出结果正是我们所期望的,s0 与s1 仍旧是截然不同的两个String 。实例因此s0==s1 的结果是false。 而s1.intern()返回的是常量池中的引用值即s0 所,以表达式s0==s1.intern()的结果是true。 假如我们希望将实例s1 存入常量池中,我们必须首先设置s0 为null, 然后请求垃圾回收器garbagecollector 回收被指向s0 的String 实例。在s0 被回收后s1.intern()方法的调用,将会把s1存入常量池。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 总的来说在执行等式比较时,应该始终使用String.equals(...)方法,而不是==运算符。如果你还是习惯性地使用==运算符,那么intern()方法可以帮助你得到正确的答案。因为当n 和m 均为String 实例的引用时,语句n.equals(m)与n.intern() ==m.intern()得到的结果是一致的。假如你打算充分利用常量池的优势那么你就应该选择String.intern()方法。</P>
<P><BR>&nbsp;</P><img src ="http://www.blogjava.net/formatmyself/aggbug/27168.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/formatmyself/" target="_blank">早餐2块2</a> 2006-01-08 19:24 <a href="http://www.blogjava.net/formatmyself/articles/27168.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java源码分析：深入探讨Iterator模式</title><link>http://www.blogjava.net/formatmyself/articles/27138.html</link><dc:creator>早餐2块2</dc:creator><author>早餐2块2</author><pubDate>Sun, 08 Jan 2006 06:39:00 GMT</pubDate><guid>http://www.blogjava.net/formatmyself/articles/27138.html</guid><wfw:comment>http://www.blogjava.net/formatmyself/comments/27138.html</wfw:comment><comments>http://www.blogjava.net/formatmyself/articles/27138.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/formatmyself/comments/commentRss/27138.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/formatmyself/services/trackbacks/27138.html</trackback:ping><description><![CDATA[java.util包中包含了一系列重要的集合类。本文将从分析源码入手，深入研究一个集合类的内部结构，以及遍历集合的迭代模式的源码实现内幕。<BR><BR>下面我们先简单讨论一个根接口Collection，然后分析一个抽象类AbstractList和它的对应Iterator接口，并仔细研究迭代子模式的实现原理。<BR><BR>本文讨论的源代码版本是JDK&nbsp;1.4.2，因为JDK&nbsp;1.5在java.util中使用了很多泛型代码，为了简化问题，所以我们还是讨论1.4版本的代码。<BR><BR>集合类的根接口Collection<BR><BR><BR>Collection接口是所有集合类的根类型。它的一个主要的接口方法是：<BR><BR>boolean&nbsp;add(Object&nbsp;c)<BR><BR><BR>add()方法将添加一个新元素。注意这个方法会返回一个boolean，但是返回值不是表示添加成功与否。仔细阅读doc可以看到，Collection规定：如果一个集合拒绝添加这个元素，无论任何原因，都必须抛出异常。这个返回值表示的意义是add()方法执行后，集合的内容是否改变了（就是元素有无数量，位置等变化），这是由具体类实现的。即：如果方法出错，总会抛出异常；返回值仅仅表示该方法执行后这个Collection的内容有无变化。<BR><BR>类似的还有：<BR><BR>boolean&nbsp;addAll(Collection&nbsp;c);<BR>boolean&nbsp;remove(Object&nbsp;o);<BR>boolean&nbsp;removeAll(Collection&nbsp;c);<BR>boolean&nbsp;remainAll(Collection&nbsp;c);<BR><BR><BR>Object[]&nbsp;toArray()方法很简单，把集合转换成数组返回。Object[]&nbsp;toArray(Object[]&nbsp;a)方法就有点复杂了，首先，返回的Object[]仍然是把集合的所有元素变成的数组，但是类型和参数a的类型是相同的，比如执行：<BR><BR>String[]&nbsp;o&nbsp;=&nbsp;(String[])c.toArray(new&nbsp;String[0]);<BR><BR>得到的o实际类型是String[]。<BR><BR>其次，如果参数a的大小装不下集合的所有元素，返回的将是一个新的数组。如果参数a的大小能装下集合的所有元素，则返回的还是a，但a的内容用集合的元素来填充。尤其要注意的是，如果a的大小比集合元素的个数还多，a后面的部分全部被置为null。<BR><BR>最后一个最重要的方法是iterator()，返回一个Iterator（迭代子），用于遍历集合的所有元素。<BR><BR>用Iterator模式实现遍历集合<BR><BR><BR>Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来，从而避免向客户端暴露集合的内部结构。<BR><BR>例如，如果没有使用Iterator，遍历一个数组的方法是使用索引：<BR><BR>for(int&nbsp;i=0;&nbsp;i&lt;array.size();&nbsp;i++)&nbsp;{&nbsp;...&nbsp;get(i)&nbsp;...&nbsp;}<BR><BR><BR>而访问一个链表（LinkedList）又必须使用while循环：<BR><BR>while((e=e.next())!=null)&nbsp;{&nbsp;...&nbsp;e.data()&nbsp;...&nbsp;}<BR><BR>以上两种方法客户端都必须事先知道集合的内部结构，访问代码和集合本身是紧耦合，无法将访问逻辑从集合类和客户端代码中分离出来，每一种集合对应一种遍历方法，客户端代码无法复用。<BR><BR>更恐怖的是，如果以后需要把ArrayList更换为LinkedList，则原来的客户端代码必须全部重写。<BR><BR>为解决以上问题，Iterator模式总是用同一种逻辑来遍历集合：<BR><BR>for(Iterator&nbsp;it&nbsp;=&nbsp;c.iterater();&nbsp;it.hasNext();&nbsp;)&nbsp;{&nbsp;...&nbsp;}<BR><BR>奥秘在于客户端自身不维护遍历集合的"指针"，所有的内部状态（如当前元素位置，是否有下一个元素）都由Iterator来维护，而这个Iterator由集合类通过工厂方法生成，因此，它知道如何遍历整个集合。<BR><BR>客户端从不直接和集合类打交道，它总是控制Iterator，向它发送"向前"，"向后"，"取当前元素"的命令，就可以间接遍历整个集合。<BR><BR>首先看看java.util.Iterator接口的定义：<BR><BR>public&nbsp;interface&nbsp;Iterator&nbsp;{<BR>boolean&nbsp;hasNext();<BR>Object&nbsp;next();<BR>void&nbsp;remove();<BR>}<BR><BR>依赖前两个方法就能完成遍历，典型的代码如下：<BR><BR>for(Iterator&nbsp;it&nbsp;=&nbsp;c.iterator();&nbsp;it.hasNext();&nbsp;)&nbsp;{<BR>Object&nbsp;o&nbsp;=&nbsp;it.next();<BR>//&nbsp;对o的操作...<BR>}<BR><BR>在JDK1.5中，还对上面的代码在语法上作了简化：<BR><BR>//&nbsp;Type是具体的类型，如String。<BR>for(Type&nbsp;t&nbsp;:&nbsp;c)&nbsp;{<BR>//&nbsp;对t的操作...<BR>}<BR><BR>每一种集合类返回的Iterator具体类型可能不同，Array可能返回ArrayIterator，Set可能返回SetIterator，Tree可能返回TreeIterator，但是它们都实现了Iterator接口，因此，客户端不关心到底是哪种Iterator，它只需要获得这个Iterator接口即可，这就是面向对象的威力。<BR><BR>Iterator源码剖析<BR><BR><BR>让我们来看看AbstracyList如何创建Iterator。首先AbstractList定义了一个内部类（inner&nbsp;class）：<BR><BR>private&nbsp;class&nbsp;Itr&nbsp;implements&nbsp;Iterator&nbsp;{<BR>...<BR>}<BR><BR><BR>而iterator()方法的定义是：<BR><BR>public&nbsp;Iterator&nbsp;iterator()&nbsp;{<BR>return&nbsp;new&nbsp;Itr();<BR>}<BR><BR>因此客户端不知道它通过Iterator&nbsp;it&nbsp;=&nbsp;a.iterator();所获得的Iterator的真正类型。<BR><BR>现在我们关心的是这个申明为private的Itr类是如何实现遍历AbstractList的：<BR><BR>private&nbsp;class&nbsp;Itr&nbsp;implements&nbsp;Iterator&nbsp;{<BR>int&nbsp;cursor&nbsp;=&nbsp;0;<BR>int&nbsp;lastRet&nbsp;=&nbsp;-1;<BR>int&nbsp;expectedModCount&nbsp;=&nbsp;modCount;<BR>}<BR><BR>Itr类依靠3个int变量（还有一个隐含的AbstractList的引用）来实现遍历，cursor是下一次next()调用时元素的位置，第一次调用next()将返回索引为0的元素。lastRet记录上一次游标所在位置，因此它总是比cursor少1。<BR><BR>变量cursor和集合的元素个数决定hasNext()：<BR><BR>public&nbsp;boolean&nbsp;hasNext()&nbsp;{<BR>return&nbsp;cursor&nbsp;!=&nbsp;size();<BR>}<BR><BR>方法next()返回的是索引为cursor的元素，然后修改cursor和lastRet的值：<BR><BR>public&nbsp;Object&nbsp;next()&nbsp;{<BR>checkForComodification();<BR>try&nbsp;{<BR>Object&nbsp;next&nbsp;=&nbsp;get(cursor);<BR>lastRet&nbsp;=&nbsp;cursor++;<BR>return&nbsp;next;<BR>}&nbsp;catch(IndexOutOfBoundsException&nbsp;e)&nbsp;{<BR>checkForComodification();<BR>throw&nbsp;new&nbsp;NoSuchElementException();<BR>}<BR>}<BR><BR>expectedModCount表示期待的modCount值，用来判断在遍历过程中集合是否被修改过。AbstractList包含一个modCount变量，它的初始值是0，当集合每被修改一次时（调用add，remove等方法），modCount加1。因此，modCount如果不变，表示集合内容未被修改。<BR><BR>Itr初始化时用expectedModCount记录集合的modCount变量，此后在必要的地方它会检测modCount的值：<BR><BR>final&nbsp;void&nbsp;checkForComodification()&nbsp;{<BR>if&nbsp;(modCount&nbsp;!=&nbsp;expectedModCount)<BR>throw&nbsp;new&nbsp;ConcurrentModificationException();<BR>}<BR><BR>如果modCount与一开始记录在expectedModeCount中的值不等，说明集合内容被修改过，此时会抛出ConcurrentModificationException。<BR><BR>这个ConcurrentModificationException是RuntimeException，不要在客户端捕获它。如果发生此异常，说明程序代码的编写有问题，应该仔细检查代码而不是在catch中忽略它。<BR><BR>但是调用Iterator自身的remove()方法删除当前元素是完全没有问题的，因为在这个方法中会自动同步expectedModCount和modCount的值：<BR><BR>public&nbsp;void&nbsp;remove()&nbsp;{<BR>...<BR>AbstractList.this.remove(lastRet);<BR>...<BR>//&nbsp;在调用了集合的remove()方法之后重新设置了expectedModCount：<BR>expectedModCount&nbsp;=&nbsp;modCount;<BR>...<BR>}<BR><BR>要确保遍历过程顺利完成，必须保证遍历过程中不更改集合的内容（Iterator的remove()方法除外），因此，确保遍历可靠的原则是只在一个线程中使用这个集合，或者在多线程中对遍历代码进行同步。<BR><BR>最后给个完整的示例：<BR><BR>Collection&nbsp;c&nbsp;=&nbsp;new&nbsp;ArrayList();<BR>c.add("abc");<BR>c.add("xyz");<BR>for(Iterator&nbsp;it&nbsp;=&nbsp;c.iterator();&nbsp;it.hasNext();&nbsp;)&nbsp;{<BR>String&nbsp;s&nbsp;=&nbsp;(String)it.next();<BR>System.out.println(s);<BR>}<BR><BR>如果你把第一行代码的ArrayList换成LinkedList或Vector，剩下的代码不用改动一行就能编译，而且功能不变，这就是针对抽象编程的原则：对具体类的依赖性最小。 <BR><img src ="http://www.blogjava.net/formatmyself/aggbug/27138.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/formatmyself/" target="_blank">早餐2块2</a> 2006-01-08 14:39 <a href="http://www.blogjava.net/formatmyself/articles/27138.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对于java类加载器的认识（2） </title><link>http://www.blogjava.net/formatmyself/articles/21330.html</link><dc:creator>早餐2块2</dc:creator><author>早餐2块2</author><pubDate>Thu, 24 Nov 2005 10:40:00 GMT</pubDate><guid>http://www.blogjava.net/formatmyself/articles/21330.html</guid><wfw:comment>http://www.blogjava.net/formatmyself/comments/21330.html</wfw:comment><comments>http://www.blogjava.net/formatmyself/articles/21330.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/formatmyself/comments/commentRss/21330.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/formatmyself/services/trackbacks/21330.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;让我们先回到java的动态性，实现java的动态性有两种方法类型：一种是隐式，另一种是显式。什么是隐式？new 这个关键字我们都认识，当我们用其将类实例化时（即将对象载入），这种就是隐式！我们再来看显式的实现方法，一种可以由java.long.Class里面的forName()方法将类实例化，其中也用到了类加载器，详情见：<A HREF="/formatmyself/articles/21291.html">认识java的Class类</A>，另一种是由也就是直接用类加载器ClassLoader来实现。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ClassLoader一些重要的方法<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A)&nbsp; 方法 loadClass <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ClassLoader.loadClass() 是 ClassLoader 的入口点。该方法的定义如下： <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class loadClass( String name, boolean resolve );<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;参数name&nbsp; JVM 需要的类的名称，如&nbsp;Person 或 java.lang.Object。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;参数 resolve 参数告诉方法是否需要解析类。在准备执行类之前，应考虑类解析。并不总是需要解析。如果 JVM 只需要知道该类是否存在或找出该类的超类，那么就不需要解析详情见：<A HREF="/formatmyself/articles/21291.html">认识java的Class类</A>&nbsp;中的forName()方法的介绍。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B)&nbsp; 方法 defineClass <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; defineClass 方法是 ClassLoader 的主要诀窍。该方法接受由原始字节组成的数组并把它转换成 Class 对象。原始数组包含如从文件系统或网络装入的数据。defineClass 管理 JVM 的许多复杂、神秘和倚赖于实现的方面 -- 它把字节码分析成运行时数据结构、校验有效性等等。不必担心，您无需亲自编写它。事实上，即使您想要这么做也不能覆盖它，因为它已被标记成final的。&nbsp;<BR>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; C)&nbsp; 方法 findSystemClass <BR>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; findSystemClass 方法从本地文件系统装入文件。它在本地文件系统中寻找类文件，如果存在，就使用 defineClass 将原始字节转换成 Class 对象，以将该文件转换成类。当运行 Java 应用程序时，这是 JVM 正常装入类的缺省机制。（Java 2 中 ClassLoader 的变动提供了关于 Java 版本 1.2 这个过程变动的详细信息。） 对于定制的 ClassLoader，只有在尝试其它方法装入类之后，再使用 findSystemClass。原因很简单：ClassLoader 是负责执行装入类的特殊步骤，不是负责所有类。例如，即使 ClassLoader 从远程的 Web 站点装入了某些类，仍然需要在本地机器上装入大量的基本 Java 库。而这些类不是我们所关心的，所以要 JVM 以缺省方式装入它们：从本地文件系统。这就是 findSystemClass 的用途。&nbsp;<BR>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; D) 方法 resolveClass <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;正如前面所提到的，可以不完全地（不带解析）装入类，也可以完全地（带解析）装入类。当编写我们自己的 loadClass 时，可以调用 resolveClass，这取决于 loadClass 的 resolve 参数的值。&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; E) 方法 findLoadedClass&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; findLoadedClass 充当一个缓存：当请求 loadClass 装入类时，它调用该方法来查看 ClassLoader 是否已装入这个类，这样可以避免重新装入已存在类所造成的麻烦。应首先调用该方法。<BR><BR>怎么组装这些方法 <BR>&nbsp; 1） 调用 findLoadedClass 来查看是否存在已装入的类。<BR>&nbsp; 2） 如果没有，那么采用那种特殊的神奇方式来获取原始字节。<BR>&nbsp; 3） 如果已有原始字节，调用 defineClass 将它们转换成 Class 对象。<BR>&nbsp; 4） 如果没有原始字节，然后调用 findSystemClass 查看是否从本地文件系统获取类。<BR>&nbsp; 5） 如果 resolve 参数是 true，那么调用 resolveClass 解析 Class 对象。<BR>&nbsp; 6） 如果还没有类，返回 ClassNotFoundException。<BR><BR>Java 2 中 ClassLoader 的变动<BR>1）loadClass 的缺省实现 <BR>&nbsp;&nbsp; 定制编写的 loadClass 方法一般尝试几种方式来装入所请求的类，如果您编写许多类，会发现一次次地在相同的、很复杂的方法上编写变量。 在 Java 1.2 中 loadClass 的实现嵌入了大多数查找类的一般方法，并使您通过覆盖 findClass 方法来定制它，在适当的时候 findClass 会调用 loadClass。 这种方式的好处是您可能不一定要覆盖 loadClass；只要覆盖 findClass 就行了，这减少了工作量。 <BR><BR>2）新方法：findClass<BR>&nbsp;&nbsp;&nbsp;&nbsp; loadClass 的缺省实现调用这个新方法。findClass 的用途包含您的 ClassLoader 的所有特殊代码，而无需要复制其它代码（例如，当专门的方法失败时，调用系统 ClassLoader）。 <BR><BR>3） 新方法：getSystemClassLoader <BR>&nbsp;&nbsp;&nbsp;&nbsp; 如果覆盖 findClass 或 loadClass，getSystemClassLoader 使您能以实际 ClassLoader 对象来访问系统 ClassLoader（而不是固定的从 findSystemClass 调用它）。 <BR>&nbsp; <BR>4） 新方法：getParent&nbsp; <BR>&nbsp;&nbsp;&nbsp; 为了将类请求委托给父代 ClassLoader，这个新方法允许 ClassLoader 获取它的父代 ClassLoader。当使用特殊方法，定制的 ClassLoader 不能找到类时，可以使用这种方法。<BR>父代 ClassLoader 被定义成创建该 ClassLoader 所包含代码的对象的 ClassLoader。&nbsp;&nbsp;&nbsp;<BR><BR><BR><BR> <BR><BR><img src ="http://www.blogjava.net/formatmyself/aggbug/21330.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/formatmyself/" target="_blank">早餐2块2</a> 2005-11-24 18:40 <a href="http://www.blogjava.net/formatmyself/articles/21330.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对于java类加载器的认识（1）</title><link>http://www.blogjava.net/formatmyself/articles/21297.html</link><dc:creator>早餐2块2</dc:creator><author>早餐2块2</author><pubDate>Thu, 24 Nov 2005 07:53:00 GMT</pubDate><guid>http://www.blogjava.net/formatmyself/articles/21297.html</guid><wfw:comment>http://www.blogjava.net/formatmyself/comments/21297.html</wfw:comment><comments>http://www.blogjava.net/formatmyself/articles/21297.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/formatmyself/comments/commentRss/21297.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/formatmyself/services/trackbacks/21297.html</trackback:ping><description><![CDATA[<P>作者：早餐2块2 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java是具有动态性，什么是动态性？有个最直观的例子：windows系统的即插即用，支持即插即用的设备可以在系统不重新启动的情况下既可以热把插使用。而java的动态性表现在：我们的程序可以不用全盘的重新编译就能对程序某部分进行更新，C#也和java一样具有动态性，而且它的这种动态性表现更为直观：直接生成windows的动态连接库文件——dll文件。而java生成的是class文件，class是怎么实现动态性的了,这个时候就全靠我们今天的主角：java的类加载器。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们都知道所有的java类都是继承了object这个类，在object这个类中有一个方法：getclass(),这个方法返回的是一个Class类对象，具体见：<A HREF="/formatmyself/articles/21291.html">认识java的Class类</A><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一旦一个类被载入JVM中，同一个类就不会被再次载入了（切记，同一个类）。这里存在一个问题就是什么是“同一个类”？正如一个对象有一个具体的状态，即标识，一个对象始终和其代码(类)相关联(见文<A HREF="/formatmyself/articles/21291.html">认识java的Class类</A>)。同理，载入JVM的类也应该有一个具体的标识，我们知道：在JAVA中，一个类用其完全匹配类名(fully qualified class name)作为标识，这里指的完全匹配类名是包名和类名。不过在JVM中一个类是用其全名再附加上一个加载类ClassLoader的实例作为唯一标识。因此，如果一个名为Pg的包中，有一个名为Cl的类，被类加载器KlassLoader的一个实例对象kl1加载，生成Cl的对象，即C1.class(这里指类，而非对象)在JVM中表示为(Cl, Pg, kl1)。这意味着两个类加载器的实例(Cl, Pg, kl1) 和 (Cl, Pg, kl2)是不同的，被它们所加载的类也因此完全不同，互不兼容的。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在java中每个类都是由某个类加载器的实体来载入的，因此在Class类的实体中，都会有字段记录载入它的类加载器的实体（当为null时，其实是指Bootstrap ClassLoader）。 在java类加载器中除了引导类加载器（既Bootstrap ClassLoader），所有的类加载器都有一个父类加载器(因为他们本身自己就是java类)。而类的加载机制是遵循一种委托模式：当类加载器有加载类的需求时，会先请求其Parent加载(依次递归),如果在其父加载器树中都没有成功加载该类，则由当前类加载器加载。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java的类加载器分为以下几种：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1，Bootstrap ClassLoader，用C++实现，一切的开始，是所有类加载器的最终父加载器。负责将一些关键的Java类，如java.lang.Object和其他一些运行时代码先加载进内存中。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2，ExtClassLoader，用java实现，是Launcher.java的内部类，编译后的名字为：Launcher$ExtClassLoader.class 。此类由Bootstrap ClassLoader加载，但由于Bootstrap ClassLoader已经脱离了java体系(c++),所以Launcher$ExtClassLoader.class的Parent(父加载器)被设置为null;它用于装载Java运行环境扩展包(jre/lib/ext)中的类，而且一旦建立其加载的路径将不再改变。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3，AppClassLoader,用java实现，也是是Launcher.java的内部类，编译后的名字为：Launcher$AppClassLoader.class 。AppClassLoader是当Bootstrap ClassLoader加载完ExtClassLoader后，再被Bootstrap ClassLoader加载。所以ExtClassLoader和AppClassLoader都是被Bootstrap ClassLoader加载，但AppClassLoader的Parent被设置为ExtClassLoader。可见Parent和由哪个类加载器来加载不一定是对应的。<BR>个类装载器是我们经常使用的，可以调用ClassLoader.getSystemClassLoader() 来获得，如果程序中没有使用类装载器相关操作设定或者自定义新的类装载器，那么我们编写的所有java类都会由它来装载。而它的查找区域就是我们常常说到的Classpath，一旦建立其加载路径也不再改变。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4，ClassLoader：一般我们自定义的ClassLoader从ClassLoader类继承而来。比如：URLClassloader是ClassLoader的一个子类，而URLClassloader也是ExtClassLoader和AppClassLoader的父类（注意不是父加载器）。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR></P><img src ="http://www.blogjava.net/formatmyself/aggbug/21297.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/formatmyself/" target="_blank">早餐2块2</a> 2005-11-24 15:53 <a href="http://www.blogjava.net/formatmyself/articles/21297.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>认识java的Class类</title><link>http://www.blogjava.net/formatmyself/articles/21291.html</link><dc:creator>早餐2块2</dc:creator><author>早餐2块2</author><pubDate>Thu, 24 Nov 2005 07:06:00 GMT</pubDate><guid>http://www.blogjava.net/formatmyself/articles/21291.html</guid><wfw:comment>http://www.blogjava.net/formatmyself/comments/21291.html</wfw:comment><comments>http://www.blogjava.net/formatmyself/articles/21291.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/formatmyself/comments/commentRss/21291.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/formatmyself/services/trackbacks/21291.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class 类是在Java语言中定义一个特定类的实现。一个类的定义包含成员变量，成员方法，还有这个类实现的接口，以及这个类的父类。Class类的对象用于表示当前运行的 Java 应用程序中的类和接口。 比如：每个数组均属于一个 Class 类对象，所有具有相同元素类型和维数的数组共享一个Class 对象。基本的 Java 类型(boolean, byte, char, short, int, long, float 和 double) 和 void 类型也可表示为 Class 对象。<BR>以下示例使用 Class 对象显示一个对象的 Class 名：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void printClassName(Object obj) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("The class of " + obj +<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; " is " + obj.getClass().getName());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR><BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们都知道所有的java类都是继承了object这个类，在object这个类中有一个方法：getclass().这个方法是用来取得该类已经被实例化了的对象的该类的引用，这个引用指向的是Class类的对象（呵呵，有点别扭）。我们自己无法生成一个Class对象（构造函数为private)，而这个Class类的对象是在当各类被调入时，由 Java 虚拟机自动创建 Class 对象，或通过类装载器中的 defineClass 方法生成。 我们生成的对象都会有个字段记录该对象所属类在CLass类的对象的所在位置。如下图所示：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <IMG height=373 alt=o_1.jpg src="http://www.blogjava.net/images/blogjava_net/formatmyself/5215/o_1.jpg" width=436 border=0><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们可以把每个Class类的对象当做众多类的代理。而且在每个Class类对象中有会有字段记录他引用的这个类的类加载器。如果该字段为null,表示该类的加载器为bootstrap loader.具体原因见：<A href="/formatmyself/articles/21297.html">对于类加载器的认识一文</A>。<BR><IMG height=424 alt=1.jpg src="http://www.blogjava.net/images/blogjava_net/formatmyself/5215/1.jpg" width=449 border=0><BR>我们知道java中有多个加载器，每个加载器能载入多个类，所以只要取得Class类对象，就可利用其getClassLoader()方法取得该类加载器的引用。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jvm为每种类管理者独一的Class对象。因此我们可以用双等号操作符来比较对象：a1.getClass()==A.class;应该返回的是true。<BR>
<DT><STRONG>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; forName(String classname)和 forName(String classname，boolean initialze,ClassLoader loader)&nbsp;&nbsp; </STRONG>方法<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 该方法返回给定串名相应的<CODE>Class</CODE> 对象。若给定一个类或接口的完整路径名，那么此方法将试图定位、装载和连接该类<FONT face=Arial>。若成功，返回该类对象。否则，抛出 ClassNotFoundException 异常。 例如，下面代码段返回名为<CODE>java.lang.Thread</CODE> 的运行 <CODE>Class</CODE> 描述器。</FONT><CODE><FONT face=Arial>Class&nbsp;t&nbsp;= Class.forName("java.lang.Thread") ;&nbsp; <FONT size=4><FONT size=3>此方法是需要指定类加载器的，当用到仅有一个String参数的forName方法时，Class对象将默认调用当前类加载器作为加载器和将第二参数为true。第二个参数说明：如果是false时，调用forName方法只是在命令类加载器载入该类，而不初始化该类的静态区块，只有当该类第一次实例化时，静态区块才被调用。当为true时，则载入时就调用静态区块。</FONT></FONT></FONT>
<DT><STRONG>getClassLoader() <BR></STRONG>获取该类的类装载器。 <BR><STRONG>getComponentType() <BR></STRONG>如果当前类表示一个数组，则返回表示该数组组件的 Class 对象，否则返回 null。<STRONG> <BR>getConstructor(Class[]) <BR></STRONG>返回当前 Class 对象表示的类的指定的公有构造子对象。<STRONG> <BR>getConstructors() <BR></STRONG>返回当前 Class 对象表示的类的所有公有构造子对象数组。<STRONG> <BR>getDeclaredConstructor(Class[]) <BR></STRONG>返回当前 Class 对象表示的类的指定已说明的一个构造子对象。 <BR><STRONG>getDeclaredConstructors() <BR></STRONG>返回当前 Class 对象表示的类的所有已说明的构造子对象数组。 <BR><STRONG>getDeclaredField(String) <BR></STRONG>返回当前 Class 对象表示的类或接口的指定已说明的一个域对象。<STRONG> <BR>getDeclaredFields() <BR></STRONG>返回当前 Class 对象表示的类或接口的所有已说明的域对象数组。<STRONG> <BR>getDeclaredMethod(String, Class[]) <BR></STRONG>返回当前 Class 对象表示的类或接口的指定已说明的一个方法对象。<STRONG> <BR>getDeclaredMethods() <BR></STRONG>返回 Class 对象表示的类或接口的所有已说明的方法数组。<STRONG> <BR>getField(String) <BR></STRONG>返回当前 Class 对象表示的类或接口的指定的公有成员域对象。<STRONG> <BR>getFields() <BR></STRONG>返回当前 Class 对象表示的类或接口的所有可访问的公有域对象数组。<STRONG> <BR>getInterfaces() <BR></STRONG>返回当前对象表示的类或接口实现的接口<STRONG>。 <BR>getMethod(String, Class[]) <BR></STRONG>返回当前 Class 对象表示的类或接口的指定的公有成员方法对象。<STRONG> <BR>getMethods() <BR></STRONG>返回当前 Class 对象表示的类或接口的所有公有成员方法对象数组，包括已声明的和从父类继承的方法。<STRONG> <BR>getModifiers() <BR></STRONG>返回该类或接口的 Java 语言修改器代码。<STRONG> <BR>getName() <BR></STRONG>返回 Class 对象表示的类型(类、接口、数组或基类型)的完整路径名字符串。<STRONG> <BR>getResource(String) <BR></STRONG>按指定名查找资源。<STRONG> <BR>getResourceAsStream(String) <BR></STRONG>用给定名查找资源。<STRONG> <BR>getSigners() <BR></STRONG>获取类标记。<STRONG> <BR>getSuperclass() <BR></STRONG>如果此对象表示除 Object 外的任一类, 那么返回此对象的父类对象。<STRONG> <BR>isArray() <BR></STRONG>如果 Class 对象表示一个数组则返回 true, 否则返回 false。<STRONG> <BR>isAssignableFrom(Class) <BR></STRONG>判定 Class 对象表示的类或接口是否同参数指定的 Class 表示的类或接口相同，或是其父类。<STRONG> <BR>isInstance(Object) <BR></STRONG>此方法是 Java 语言 instanceof 操作的动态等价方法。<STRONG> <BR>isInterface() <BR></STRONG>判定指定的 Class 对象是否表示一个接口类型。<STRONG> <BR>isPrimitive() <BR></STRONG>判定指定的 Class 对象是否表示一个 Java 的基类型<STRONG>。 <BR>newInstance() <BR></STRONG>创建类的新实例。<STRONG> <BR>toString() <BR></STRONG>将对象转换为字符串。&nbsp;<STRONG>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR></STRONG></CODE></DT><img src ="http://www.blogjava.net/formatmyself/aggbug/21291.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/formatmyself/" target="_blank">早餐2块2</a> 2005-11-24 15:06 <a href="http://www.blogjava.net/formatmyself/articles/21291.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于jdk，jvm，jre之间的关系</title><link>http://www.blogjava.net/formatmyself/articles/21247.html</link><dc:creator>早餐2块2</dc:creator><author>早餐2块2</author><pubDate>Thu, 24 Nov 2005 03:01:00 GMT</pubDate><guid>http://www.blogjava.net/formatmyself/articles/21247.html</guid><wfw:comment>http://www.blogjava.net/formatmyself/comments/21247.html</wfw:comment><comments>http://www.blogjava.net/formatmyself/articles/21247.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/formatmyself/comments/commentRss/21247.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/formatmyself/services/trackbacks/21247.html</trackback:ping><description><![CDATA[<P>作者：<A id=BlogTitleLink HREF="/formatmyself/"><FONT color=#6b86b3>早餐2块2</FONT></A><BR><BR>dk：java开发包，包括java开发工具：javac.exe，jar.exe等<BR>jvm：java虚拟机。以jvm.dll文件存在于计算机(windows平台)<BR>jre：java运行环境。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般来说（可以选择),如果安装了jdk，计算机就会存在两套jre,一套位于jdk安装目录下的/jre子目录中，另一套位于c:\Program File\Java\下。java的程序必须依靠jre才能执行，jre包含了jvm，也就是java虚拟机。所以只要计算机中正确安装了jre就能执行java程序。为什么jre需要安装两套了，因为jdk中有很多的java开发工具（jdk安装目录\lib\tools.jar)本身就是用java开发的，如果要使用，必须要自行附一套jre才行，也就是jdk下面jre存在的目的（其实也可以用来执行我们的程序)，而c:\Program File\Java\下的是用来执行我们所写的java程序的。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当我们运行java xxx时，java.exe是按照下列顺序寻找jre的：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1，自己目录下有无jre目录<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2，父目录下的jre目录<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3，查询 windows Register(HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment\<BR>所以我们程序的运行与java.exe是哪个目录下和这个java.exe所指引的jre很有关系。而java.exe的指定是根据系统的path变量。<BR><BR><BR><BR><BR>参考书籍：《java深度历险》</P><img src ="http://www.blogjava.net/formatmyself/aggbug/21247.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/formatmyself/" target="_blank">早餐2块2</a> 2005-11-24 11:01 <a href="http://www.blogjava.net/formatmyself/articles/21247.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>给Log4j配上数据库连接池</title><link>http://www.blogjava.net/formatmyself/articles/18161.html</link><dc:creator>早餐2块2</dc:creator><author>早餐2块2</author><pubDate>Fri, 04 Nov 2005 08:24:00 GMT</pubDate><guid>http://www.blogjava.net/formatmyself/articles/18161.html</guid><wfw:comment>http://www.blogjava.net/formatmyself/comments/18161.html</wfw:comment><comments>http://www.blogjava.net/formatmyself/articles/18161.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/formatmyself/comments/commentRss/18161.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/formatmyself/services/trackbacks/18161.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作者：&nbsp; <A id=BlogTitleLink HREF="/formatmyself/"><FONT color=#6b86b3><a title="" href="http://www.blogjava.net/formatmyself/" target="_blank">早餐2块2</a></FONT></A>&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们都知道log4j是一个优秀的开源日志记录项目，我们不仅可以对输出的日志的格式自定义，还可以自己定义日志输出的目的地，比如：屏幕，文本文件，数据库，甚至能通过socket输出。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;现在让我们对日志输出到数据库来进行配置<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;配置如下：<BR>#---JDBC ---输出到数据库<BR># JDBCAppender log4j.properties file<BR>#log4j.rootCategory=WARN,JDBC<BR># APPENDER JDBC<BR>log4j.appender.JDBC=org.apache.log4j.jdbc.JDBCAppender<BR>log4j.appender.JDBC.driver=<FONT face="Courier New">com.mysql.jdbc.Driver</FONT><BR>log4j.appender.JDBC.URL=<FONT face="Courier New">jdbc:mysql://localhost:3306/test</FONT><BR>log4j.appender.JDBC.user=use<BR>log4j.appender.JDBC.password=password<BR>log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout<BR>log4j.appender.JDBC.sql=INSERT INTO LOGGING (log_date, log_level, location, message) VALUES ('%d{ISO8601}', '%-5p', '%C,%L', '%m')<BR><BR>表结构如下：<BR>log_date&nbsp;&nbsp; varchar2(50)<BR>log_level&nbsp; varchar2(5)<BR>location&nbsp;&nbsp; varchar2(100)&nbsp; <BR>message&nbsp;&nbsp;&nbsp; varchar2(1000)<BR>笔者照做，但没有运行成功，而且此种方法是利用传统的数据库连接方法，对于数据库的管理和效率严重不足，在现在这个连接池横行的时代,为什么我们不能给给Log4j配上连接池，让Log4j利用数据连接池的连接和数据库进行通讯。现查看Log4j的Api,发现JDBCAppender这个类有以下几段话：<STRONG><FONT color=#ff2222>WARNING: This version of JDBCAppender is very likely to be completely replaced in the future. Moreoever, it does not log exceptions</FONT></STRONG>. The JDBCAppender provides for sending log events to a database. 
<P>For use as a base class: 
<UL>
<LI>Override <CODE>getConnection()</CODE> to pass any connection you want. Typically this is used to enable application wide connection pooling. 
<LI>Override <CODE>closeConnection(Connection con)</CODE> -- if you override getConnection make sure to implement <CODE>closeConnection</CODE> to handle the connection you generated. Typically this would return the connection to the pool it came from. 
<LI>Override <CODE>getLogStatement(LoggingEvent event)</CODE> to produce specialized or dynamic statements. The default uses the sql option value.</LI></UL>
<P>原来log4j建议我们把其提供的JDBCAppender作为基类来使用，然后Override三个父类的方法：<FONT face="Courier New">getConnection(),</FONT><FONT face="Courier New">closeConnection(Connection con)和getLogStatement(LoggingEvent event)。<BR>原来如此，那就写一个子类JDBCPoolAppender来替代这个JDBCAppender<BR>JDBCPoolAppender代码和其相关代码如下：<BR><BR>JDBCPoolAppender.java:<BR><BR>package common.log;<BR>import java.sql.Connection;<BR>import org.apache.log4j.spi.LoggingEvent;<BR>import java.sql.SQLException;<BR>import java.sql.Statement;<BR>import java.util.Iterator;<BR>import org.apache.log4j.spi.ErrorCode;<BR>import org.apache.log4j.PatternLayout;<BR>import common.sql.MyDB;<BR>import common.sql.GeneralDb;<BR><BR>public class JDBCPoolAppender extends org.apache.log4j.jdbc.JDBCAppender {<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <FONT color=#0000ff>private MyDB mydb = null;&nbsp;&nbsp;<BR></FONT>&nbsp;&nbsp;&nbsp; protected String sqlname=""; //增加一个数据库jndiName的属性<BR>&nbsp;&nbsp;&nbsp; protected Connection connection = null;<BR>&nbsp;&nbsp;&nbsp; protected String sqlStatement = "";<BR>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * size of LoggingEvent buffer before writting to the database.<BR>&nbsp;&nbsp;&nbsp;&nbsp; * Default is 1.<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; protected int bufferSize = 1;</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; public JDBCPoolAppender() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super();<BR>&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * ArrayList holding the buffer of Logging Events.<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; public void append(LoggingEvent event) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer.add(event);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (buffer.size() &gt;= bufferSize)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flushBuffer();<BR>&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * By default getLogStatement sends the event to the required Layout object.<BR>&nbsp;&nbsp;&nbsp;&nbsp; * The layout will format the given pattern into a workable SQL string.<BR>&nbsp;&nbsp;&nbsp;&nbsp; *<BR>&nbsp;&nbsp;&nbsp;&nbsp; * Overriding this provides direct access to the LoggingEvent<BR>&nbsp;&nbsp;&nbsp;&nbsp; * when constructing the logging statement.<BR>&nbsp;&nbsp;&nbsp;&nbsp; *<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; protected String getLogStatement(LoggingEvent event) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return getLayout().format(event);<BR>&nbsp;&nbsp;&nbsp; }</FONT></P>
<P><FONT face="Courier New">&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; *<BR>&nbsp;&nbsp;&nbsp;&nbsp; * Override this to provide an alertnate method of getting<BR>&nbsp;&nbsp;&nbsp;&nbsp; * connections (such as caching).&nbsp; One method to fix this is to open<BR>&nbsp;&nbsp;&nbsp;&nbsp; * connections at the start of flushBuffer() and close them at the<BR>&nbsp;&nbsp;&nbsp;&nbsp; * end.&nbsp; I use a connection pool outside of JDBCAppender which is<BR>&nbsp;&nbsp;&nbsp;&nbsp; * accessed in an override of this method.<BR>&nbsp;&nbsp;&nbsp;&nbsp; * */<BR>&nbsp;&nbsp;&nbsp; protected void execute(String sql) throws SQLException {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Connection con = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Statement stmt = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; con = getConnection();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt = con.createStatement();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt.executeUpdate(sql);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (SQLException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (stmt != null)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw e;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stmt.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; closeConnection(con);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //System.out.println("Execute: " + sql);<BR>&nbsp;&nbsp;&nbsp; }</FONT></P><FONT face="Courier New">
<P><BR>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * Override this to return the connection to a pool, or to clean up the<BR>&nbsp;&nbsp;&nbsp;&nbsp; * resource.<BR>&nbsp;&nbsp;&nbsp;&nbsp; *<BR>&nbsp;&nbsp;&nbsp;&nbsp; * The default behavior holds a single connection open until the appender<BR>&nbsp;&nbsp;&nbsp;&nbsp; * is closed (typically when garbage collected).<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; protected void closeConnection(Connection con) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mydb=null;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (connection != null &amp;&amp; !connection.isClosed())<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connection.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (SQLException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; errorHandler.error("Error closing connection", e,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ErrorCode.GENERIC_FAILURE);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;Override 此函数来利用连接池返回一个Connetion对象<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; <FONT color=#0000ff>protected Connection getConnection() throws SQLException {&nbsp; <BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#0000ff>mydb = GeneralDb.getInstance(sqlname);&nbsp;&nbsp;</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#0000ff>connection = mydb.getConnection();&nbsp;</FONT>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; errorHandler.error("Error opening connection", e, ErrorCode.GENERIC_FAILURE);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return connection;<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * Closes the appender, flushing the buffer first then closing the default<BR>&nbsp;&nbsp;&nbsp;&nbsp; * connection if it is open.<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; public void close() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flushBuffer();</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (connection != null &amp;&amp; !connection.isClosed())<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connection.close();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (SQLException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; errorHandler.error("Error closing connection", e,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ErrorCode.GENERIC_FAILURE);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.closed = true;<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * loops through the buffer of LoggingEvents, gets a<BR>&nbsp;&nbsp;&nbsp;&nbsp; * sql string from getLogStatement() and sends it to execute().<BR>&nbsp;&nbsp;&nbsp;&nbsp; * Errors are sent to the errorHandler.<BR>&nbsp;&nbsp;&nbsp;&nbsp; *<BR>&nbsp;&nbsp;&nbsp;&nbsp; * If a statement fails the LoggingEvent stays in the buffer!<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; public void flushBuffer() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Do the actual logging<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; removes.ensureCapacity(buffer.size());<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (Iterator i = buffer.iterator(); i.hasNext(); ) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LoggingEvent logEvent = (LoggingEvent) i.next();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String sql = getLogStatement(logEvent);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;execute(sql);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; removes.add(logEvent);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (SQLException e) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; errorHandler.error("Failed to excute sql", e,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ErrorCode.FLUSH_FAILURE);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // remove from the buffer any events that were reported<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer.removeAll(removes);</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // clear the buffer of reported events<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; removes.clear();<BR>&nbsp;&nbsp;&nbsp; }</P>
<P><BR>&nbsp;&nbsp;&nbsp; /** closes the appender before disposal */<BR>&nbsp;&nbsp;&nbsp; public void finalize() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; close();<BR>&nbsp;&nbsp;&nbsp; }</P>
<P><BR>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * JDBCAppender requires a layout.<BR>&nbsp;&nbsp;&nbsp;&nbsp; * */<BR>&nbsp;&nbsp;&nbsp; public boolean requiresLayout() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<BR>&nbsp;&nbsp;&nbsp; }</P>
<P><BR>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; *<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; public void setSql(String s) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sqlStatement = s;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (getLayout() == null) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.setLayout(new PatternLayout(s));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((PatternLayout) getLayout()).setConversionPattern(s);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp; }</P>
<P><BR>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * Returns pre-formated statement eg: insert into LogTable (msg) values ("%m")<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; public String getSql() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return sqlStatement;<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#0000ff>public void setSqlname(String sqlname){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sqlname=sqlname;<BR>&nbsp;&nbsp;&nbsp; }<BR></FONT>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;<FONT color=#0000ff> public String getSqlname(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return sqlname;<BR>&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; </FONT></P>
<P><BR>&nbsp;&nbsp;&nbsp; public void setBufferSize(int newBufferSize) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bufferSize = newBufferSize;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buffer.ensureCapacity(bufferSize);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; removes.ensureCapacity(bufferSize);<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; public int getBufferSize() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return bufferSize;<BR>&nbsp;&nbsp;&nbsp; }<BR>}<BR></FONT></P><FONT face="Courier New">
<P><BR>MyDB.java:<BR>package common.sql;<BR>import java.sql.*;<BR>import com.codestudio.sql.*;&nbsp; //引入开源项目Poolman数据库连接池的包</P>
<P>public class MyDB {<BR>&nbsp;&nbsp;&nbsp; public static final String module = MyDB.class.getName();<BR>&nbsp;&nbsp;&nbsp; private String dbName = "";<BR>&nbsp;&nbsp;&nbsp; private PoolMan plmn = null;</P>
<P><BR>&nbsp;&nbsp;&nbsp;&nbsp;public MyDB(String dbName) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (plmn == null) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; plmn = (PoolMan) Class.forName("com.codestudio.sql.PoolMan").<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newInstance();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception ec) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(ec.toString()+module);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.dbName = dbName;<BR>&nbsp;&nbsp;&nbsp; }</P>
<P><BR>&nbsp;&nbsp;&nbsp; private Connection getNewConnection() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Connection conn = null;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn = plmn.connect("jdbc:poolman://" + dbName);&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.setAutoCommit(true);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception ec) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(ec.toString()+"First:Connect sqlsever failed"+module);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(1000);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn = plmn.connect("jdbc:poolman://" + dbName);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.setAutoCommit(true);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception ecs) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(ecs.toString()+"Again:Connect sqlsever faile"+module);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return conn;<BR>&nbsp;&nbsp;&nbsp; }</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;public Connection getConnection() {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return getNewConnection();<BR>&nbsp;&nbsp;&nbsp; }<BR>}<BR>GeneralDb.java:<BR><BR></FONT><FONT face="Courier New">package common.sql;</FONT></P>
<P><FONT face="Courier New">import java.util.*;</FONT></P>
<P><FONT face="Courier New">public class GeneralDb {<BR>&nbsp;&nbsp;&nbsp; private static Hashtable dbPool; <BR>&nbsp;&nbsp;&nbsp; public static MyDB getInstance(String dbname) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (dbPool == null) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbPool = new Hashtable();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MyDB db = (MyDB) dbPool.get(dbname);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (db == null) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; db = new MyDB(dbname);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dbPool.put(dbname, db); <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return db;<BR>&nbsp;&nbsp;&nbsp; }<BR>}</FONT></P>
<P><FONT face="Courier New">Log4j数据库连接池的配置如下：<BR>log4j.appender.JDBC=common.log.JDBCPoolAppender <BR>log4j.appender.JDBC.sqlname=log<BR>log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout<BR>log4j.appender.JDBC.sql=INSERT INTO LOGGING (log_date, log_level, location, message) VALUES ('%d{ISO8601}', '%-5p', '%C,%L', '%m')<BR><BR><BR>poolman.xml配置如下：<BR><?xml version="1.0" encoding="UTF-8"?><BR><POOLMAN>〈?xml version="1.0" encoding="UTF-8"?&gt;<BR>〈poolman&gt;<BR>&nbsp; 〈management-mode&gt;local〈/management-mode&gt;<BR>&nbsp; 〈datasource&gt;<BR>&nbsp;&nbsp;&nbsp; 〈dbname&gt;log</DBNAME>〈/dbname&gt;<BR>&nbsp;&nbsp;&nbsp; 〈jndiName&gt;log</JNDINAME>〈/jndiName&gt;<BR>&nbsp;&nbsp;&nbsp; 〈driver&gt;com.mysql.jdbc.Driver〈/driver&gt;<BR>&nbsp;&nbsp;&nbsp; 〈url&gt;jdbc:mysql://localhost:3306/test〈/url&gt;<BR>&nbsp;&nbsp;&nbsp; 〈username&gt;use</USERNAME>〈/username&gt;<BR>&nbsp;&nbsp;&nbsp; 〈password&gt;password</PASSWORD>〈/password&gt;<BR>&nbsp;&nbsp;&nbsp; 〈minimumSize&gt;0〈/minimumSize&gt;<BR>&nbsp;&nbsp;&nbsp; 〈maximumSize&gt;10〈/maximumSize&gt;<BR>&nbsp;&nbsp;&nbsp; 〈logFile&gt;logs/mysql.log〈/logFile&gt;<BR>&nbsp; 〈/datasource&gt;</FONT></P>
<P><FONT face="Courier New">〈/poolman&gt;<BR>&nbsp;&nbsp;<MANAGEMENT-MODE>&nbsp; </DATASOURCE><BR></FONT><FONT face="Courier New"></POOLMAN><BR>运行成功！对于JDBCPoolAppender的属性（比如sqlname属性）我们可以利用Log4j的反射机制随便添加，只要在配置文件给其附上值即可应用，而原来的父类里面的一些属性（username什么的)和其get,set方法由于在连接池中不需要，所以删除。而在JDBCPoolAppender类中，我也只是将<FONT color=#0000ff>getConnection </FONT><FONT color=#000000>方法Override ，在这个方法中我们可以根据需要生成我们的Connection对象，另外两个方法大家可以根据需求来决定怎样Override。：）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></FONT><BR><BR>&nbsp;</P><img src ="http://www.blogjava.net/formatmyself/aggbug/18161.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/formatmyself/" target="_blank">早餐2块2</a> 2005-11-04 16:24 <a href="http://www.blogjava.net/formatmyself/articles/18161.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>System.getProperty()参数大全 </title><link>http://www.blogjava.net/formatmyself/articles/18017.html</link><dc:creator>早餐2块2</dc:creator><author>早餐2块2</author><pubDate>Thu, 03 Nov 2005 13:45:00 GMT</pubDate><guid>http://www.blogjava.net/formatmyself/articles/18017.html</guid><wfw:comment>http://www.blogjava.net/formatmyself/comments/18017.html</wfw:comment><comments>http://www.blogjava.net/formatmyself/articles/18017.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/formatmyself/comments/commentRss/18017.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/formatmyself/services/trackbacks/18017.html</trackback:ping><description><![CDATA[<P>System.getProperty()参数大全 <BR>查资料用: <BR>java.version Java Runtime Environment version <BR>java.vendor Java Runtime Environment vendor <BR>java.vendor.url Java vendor URL <BR>java.home Java installation directory <BR>java.vm.specification.version Java Virtual Machine specification version <BR>java.vm.specification.vendor Java Virtual Machine specification vendor <BR>java.vm.specification.name Java Virtual Machine specification name <BR>java.vm.version Java Virtual Machine implementation version <BR>java.vm.vendor Java Virtual Machine implementation vendor <BR>java.vm.name Java Virtual Machine implementation name <BR>java.specification.version Java Runtime Environment specification version <BR>java.specification.vendor Java Runtime Environment specification vendor <BR>java.specification.name Java Runtime Environment specification name <BR>java.class.version Java class format version number <BR>java.class.path Java class path <BR>java.library.path List of paths to search when loading libraries <BR>java.io.tmpdir Default temp file path </P>
<P>java.compiler Name of JIT compiler to use <BR>java.ext.dirs Path of extension directory or directories <BR>os.name Operating system name <BR>os.arch Operating system architecture <BR>os.version Operating system version <BR>file.separator File separator ("/" on UNIX) path.separator Path separator (":" on UNIX) <BR>line.separator Line separator ("\n" on UNIX) <BR>user.name User's account name <BR>user.home User's home directory <BR>user.dir User's current working directory<BR></P><img src ="http://www.blogjava.net/formatmyself/aggbug/18017.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/formatmyself/" target="_blank">早餐2块2</a> 2005-11-03 21:45 <a href="http://www.blogjava.net/formatmyself/articles/18017.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java/J2EE中文问题终极解决之道</title><link>http://www.blogjava.net/formatmyself/articles/18016.html</link><dc:creator>早餐2块2</dc:creator><author>早餐2块2</author><pubDate>Thu, 03 Nov 2005 13:39:00 GMT</pubDate><guid>http://www.blogjava.net/formatmyself/articles/18016.html</guid><wfw:comment>http://www.blogjava.net/formatmyself/comments/18016.html</wfw:comment><comments>http://www.blogjava.net/formatmyself/articles/18016.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/formatmyself/comments/commentRss/18016.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/formatmyself/services/trackbacks/18016.html</trackback:ping><description><![CDATA[<P>板桥里人 <A href="http://www.jdon.com/">http://www.jdon.com</A> 2005/06/29</P>
<P>　　Java中文问题一直困扰着很多初学者，如果了解了Java系统的中文问题原理，我们就可以对中文问题能够采取根本的解决之道。</P>
<P>　　最古老的解决方案是使用String的字节码转换，这种方案问题是不方便，我们需要破坏对象封装性，进行字节码转换。</P>
<P>　　还有一种方式是对J2EE容器进行编码设置，如果J2EE应用系统脱离该容器，则会发生乱码，而且指定容器配置不符合J2EE应用和容器分离的原则。</P>
<P>　　在Java内部运算中，涉及到的所有字符串都会被转化为UTF-8编码来进行运算。那么，在被Java转化之前，字符串是什么样的字符集？ Java总是根据操作系统的默认编码字符集来决定字符串的初始编码，而且Java系统的输入和输出的都是采取操作系统的默认编码。</P>
<P>　　因此，如果能统一Java系统的输入、输出和操作系统3者的编码字符集合，将能够使Java系统正确处理和显示汉字。这是处理Java系统汉字的一个原则，但是在实际项目中，能够正确抓住和控制住Java系统的输入和输出部分是比较难的。J2EE中，由于涉及到外部浏览器和数据库等，所以中文问题乱码显得非常突出。</P>
<P>　　J2EE应用程序是运行在J2EE容器中。在这个系统中，输入途径有很多种：一种是通过页面表单打包成请求（request）发往服务器的；第二种是通过数据库读入；还有第3种输入比较复杂，JSP在第一次运行时总是被编译成Servlet，JSP中常常包含中文字符，那么编译使用javac时，Java将根据默认的操作系统编码作为初始编码。除非特别指定，如在Jbuilder/eclipse中可以指定默认的字符集。</P>
<P>　　输出途径也有几种：第一种是JSP页面的输出。由于JSP页面已经被编译成Servlet，那么在输出时，也将根据操作系统的默认编码来选择输出编码，除非指定输出编码方式；还有输出途径是数据库，将字符串输出到数据库。</P>
<P>　　由此看来，一个J2EE系统的输入输出是非常复杂，而且是动态变化的，而Java是跨平台运行的，在实际编译和运行中，都可能涉及到不同的操作系统，如果任由Java自由根据操作系统来决定输入输出的编码字符集，这将不可控制地出现乱码。</P>
<P>　　正是由于Java的跨平台特性，使得字符集问题必须由具体系统来统一解决，所以在一个Java应用系统中，解决中文乱码的根本办法是明确指定整个应用系统统一字符集。</P>
<P>　　指定统一字符集时，到底是指定ISO8859_1 、GBK还是UTF-8呢？ </P>
<P>　　（1）如统一指定为ISO8859_1，因为目前大多数软件都是西方人编制的，他们默认的字符集就是ISO8859_1，包括操作系统Linux和数据库MySQL等。这样，如果指定Jive统一编码为ISO8859_1，那么就有下面3个环节必须把握：</P>
<P>　　开发和编译代码时指定字符集为ISO8859_1。</P>
<P>　　运行操作系统的默认编码必须是ISO8859_1，如Linux。</P>
<P>　　在JSP头部声明：&lt;%@ page contentType="text/html;charset=ISO8859_1" %&gt;。</P>
<P>　　（2）如果统一指定为GBK中文字符集，上述3个环节同样需要做到，不同的是只能运行在默认编码为GBK的操作系统，如中文Windows。</P>
<P>　　统一编码为ISO8859_1和GBK虽然带来编制代码的方便，但是各自只能在相应的操作系统上运行。但是也破坏了Java跨平台运行的优越性，只在一定范围内行得通。例如，为了使得GBK编码在linux上运行，设置Linux编码为GBK。</P>
<P>　　那么有没有一种除了应用系统以外不需要进行任何附加设置的中文编码根本解决方案呢？</P>
<P>　　将Java/J2EE系统的统一编码定义为UTF-8。UTF-8编码是一种兼容所有语言的编码方式，惟一比较麻烦的就是要找到应用系统的所有出入口，然后使用UTF-8去“结扎”它。</P>
<P>　　一个J2EE应用系统需要做下列几步工作：</P>
<P>开发和编译代码时指定字符集为UTF-8。JBuilder和Eclipse都可以在项目属性中设置。 <BR>使用过滤器，如果所有请求都经过一个Servlet控制分配器，那么使用Servlet的filter执行语句，将所有来自浏览器的请求（request）转换为UTF-8，因为浏览器发过来的请求包根据浏览器所在的操作系统编码，可能是各种形式编码。关键一句：<BR>request.setCharacterEncoding("UTF-8")。<BR>网上有此filter的源码，Jdon框架源码中com.jdon.util.SetCharacterEncodingFilter<BR>需要配置web.xml 激活该Filter。 <BR>在JSP头部声明：&lt;%@ page contentType="text/html;charset= UTF-8" %&gt;。 <BR>在Jsp的html代码中，声明UTF-8:<BR>&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"&gt; <BR>设定数据库连接方式是UTF-8。例如连接MYSQL时配置URL如下：<BR>jdbc:mysql://localhost:3306/test?useUnicode=true&amp;amp;characterEncoding=UTF-8<BR>一般数据库都可以通过管理设置设定UTF-8 <BR>其他和外界交互时能够设定编码时就设定UTF-8，例如读取文件，操作XML等。 <BR>　　　　 笔者以前在Jsp/Servlet时就采取这个原则，后来使用Struts、Tapestry、EJB、Hibernate、Jdon等框架时，从未被乱码困扰过，可以说适合各种架构。希望本方案供更多初学者分享，减少Java/J2EE的第一个拦路虎，也避免因为采取一些临时解决方案，导致中文问题一直出现在新的技术架构中。 <BR>　　相关J2EE中文问题解决的源码系统可参考：按这里 </P>
<P>　　欢迎进入讨论 也欢迎提出例外案例<BR>&nbsp;<BR></P><img src ="http://www.blogjava.net/formatmyself/aggbug/18016.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/formatmyself/" target="_blank">早餐2块2</a> 2005-11-03 21:39 <a href="http://www.blogjava.net/formatmyself/articles/18016.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>