﻿<?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-TSH,SSH开发-随笔分类-java</title><link>http://www.blogjava.net/yc1354/category/19678.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 18 Oct 2007 08:14:07 GMT</lastBuildDate><pubDate>Thu, 18 Oct 2007 08:14:07 GMT</pubDate><ttl>60</ttl><item><title>同步synchornized方法与方法块</title><link>http://www.blogjava.net/yc1354/archive/2007/10/16/153179.html</link><dc:creator>赵永超</dc:creator><author>赵永超</author><pubDate>Tue, 16 Oct 2007 02:43:00 GMT</pubDate><guid>http://www.blogjava.net/yc1354/archive/2007/10/16/153179.html</guid><wfw:comment>http://www.blogjava.net/yc1354/comments/153179.html</wfw:comment><comments>http://www.blogjava.net/yc1354/archive/2007/10/16/153179.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yc1354/comments/commentRss/153179.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yc1354/services/trackbacks/153179.html</trackback:ping><description><![CDATA[<p>打个比方：一个object就像一个大房子，大门永远打开。房子里有很多房间（也就是方法）。这些房间有上锁的（synchronized方法），和不上锁之分（普通方法）。房门口放着一把钥匙（key），这把钥匙可以打开所有上锁的房间。另外我把所有想调用该对象方法的线程比喻成想进入这房子某个房间的人。所有的东西就这么多了，下面我们看看这些东西之间如何作用的。</p>
<p>在此我们先来明确一下我们的前提条件。该对象至少有一个synchronized方法，否则这个key还有啥意义。当然也就不会有我们的这个主题了。</p>
<p>一个人想进入某间上了锁的房间，他来到房子门口，看见钥匙在那儿（说明暂时还没有其他人要使用上锁的房间）。于是他走上去拿到了钥匙，并且按照自己的计划使用那些房间。注意一点，他每次使用完一次上锁的房间后会马上把钥匙还回去。即使他要连续使用两间上锁的房间，中间他也要把钥匙还回去，再取回来。</p>
<p>因此，普通情况下钥匙的使用原则是：&#8220;随用随借，用完即还。&#8221;</p>
<p>这时其他人可以不受限制的使用那些不上锁的房间，一个人用一间可以，两个人用一间也可以，没限制。但是如果当某个人想要进入上锁的房间，他就要跑到大门口去看看了。有钥匙当然拿了就走，没有的话，就只能等了。</p>
<p>要是很多人在等这把钥匙，等钥匙还回来以后，谁会优先得到钥匙？Not guaranteed。象前面例子里那个想连续使用两个上锁房间的家伙，他中间还钥匙的时候如果还有其他人在等钥匙，那么没有任何保证这家伙能再次拿到。（JAVA规范在很多地方都明确说明不保证，象Thread.sleep()休息后多久会返回运行，相同优先权的线程那个首先被执行，当要访问对象的锁被释放后处于等待池的多个线程哪个会优先得到，等等。我想最终的决定权是在JVM，之所以不保证，就是因为JVM在做出上述决定的时候，绝不是简简单单根据一个条件来做出判断，而是根据很多条。而由于判断条件太多，如果说出来可能会影响JAVA的推广，也可能是因为知识产权保护的原因吧。SUN给了个不保证就混过去了。无可厚非。但我相信这些不确定，并非完全不确定。因为计算机这东西本身就是按指令运行的。即使看起来很随机的现象，其实都是有规律可寻。学过计算机的都知道，计算机里随机数的学名是伪随机数，是人运用一定的方法写出来的，看上去随机罢了。另外，或许是因为要想弄的确定太费事，也没多大意义，所以不确定就不确定了吧。）</p>
<p>再来看看同步代码块。和同步方法有小小的不同。</p>
<p>1.从尺寸上讲，同步代码块比同步方法小。你可以把同步代码块看成是没上锁房间里的一块用带锁的屏风隔开的空间。</p>
<p>2.同步代码块还可以人为的指定获得某个其它对象的key。就像是指定用哪一把钥匙才能开这个屏风的锁，你可以用本房的钥匙；你也可以指定用另一个房子的钥匙才能开，这样的话，你要跑到另一栋房子那儿把那个钥匙拿来，并用那个房子的钥匙来打开这个房子的带锁的屏风。</p>
<p>记住你获得的那另一栋房子的钥匙，并不影响其他人进入那栋房子没有锁的房间。</p>
<p>为什么要使用同步代码块呢？我想应该是这样的：首先对程序来讲同步的部分很影响运行效率，而一个方法通常是先创建一些局部变量，再对这些变量做一些操作，如运算，显示等等；而同步所覆盖的代码越多，对效率的影响就越严重。因此我们通常尽量缩小其影响范围。如何做？同步代码块。我们只把一个方法中该同步的地方同步，比如运算。</p>
<p>另外，同步代码块可以指定钥匙这一特点有个额外的好处，是可以在一定时期内霸占某个对象的key。还记得前面说过普通情况下钥匙的使用原则吗。现在不是普通情况了。你所取得的那把钥匙不是永远不还，而是在退出同步代码块时才还。</p>
<p>还用前面那个想连续用两个上锁房间的家伙打比方。怎样才能在用完一间以后，继续使用另一间呢。用同步代码块吧。先创建另外一个线程，做一个同步代码块，把那个代码块的锁指向这个房子的钥匙。然后启动那个线程。只要你能在进入那个代码块时抓到这房子的钥匙，你就可以一直保留到退出那个代码块。也就是说你甚至可以对本房内所有上锁的房间遍历，甚至再sleep(10*60*1000)，而房门口却还有1000个线程在等这把钥匙呢。很过瘾吧。</p>
<p>在此对sleep()方法和钥匙的关联性讲一下。一个线程在拿到key后，且没有完成同步的内容时，如果被强制sleep()了，那key还一直在它那儿。直到它再次运行，做完所有同步内容，才会归还key。记住，那家伙只是干活干累了，去休息一下，他并没干完他要干的事。为了避免别人进入那个房间把里面搞的一团糟，即使在睡觉的时候他也要把那唯一的钥匙戴在身上。</p>
<p>最后，也许有人会问，为什么要一把钥匙通开，而不是一个钥匙一个门呢？我想这纯粹是因为复杂性问题。一个钥匙一个门当然更安全，但是会牵扯好多问题。钥匙的产生，保管，获得，归还等等。其复杂性有可能随同步方法的增加呈几何级数增加，严重影响效率。</p>
<p>这也算是一个权衡的问题吧。为了增加一点点安全性，导致效率大大降低，是多么不可取啊。</p>
<p>摘自：http://www.54bk.com/more.asp?name=czp&amp;id=2097</p>
<p>一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时，一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。</p>
<p>二、然而，当一个线程访问object的一个synchronized(this)同步代码块时，另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。</p>
<p>三、尤其关键的是，当一个线程访问object的一个synchronized(this)同步代码块时，其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。</p>
<p>四、第三个例子同样适用其它同步代码块。也就是说，当一个线程访问object的一个synchronized(this)同步代码块时，它就获得了这个object的对象锁。结果，其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。</p>
<p>五、以上规则对其它对象锁同样适用.</p>
<p>举例说明：</p>
<p>一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时，一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。</p>
<p>package ths;</p>
<p>public class Thread1 implements Runnable { <br />
public void run() { <br />
synchronized(this) { <br />
for (int i = 0; i &lt; 5; i++) { <br />
System.out.println(Thread.currentThread().getName() + " synchronized loop " + i); <br />
} <br />
} <br />
} <br />
public static void main(String[] args) { <br />
Thread1 t1 = new Thread1(); <br />
Thread ta = new Thread(t1, "A"); <br />
Thread tb = new Thread(t1, "B"); <br />
ta.start(); <br />
tb.start(); <br />
} <br />
}</p>
<p>结果：</p>
<p>A synchronized loop 0 <br />
A synchronized loop 1 <br />
A synchronized loop 2 <br />
A synchronized loop 3 <br />
A synchronized loop 4 <br />
B synchronized loop 0 <br />
B synchronized loop 1 <br />
B synchronized loop 2 <br />
B synchronized loop 3 <br />
B synchronized loop 4</p>
<p>二、然而，当一个线程访问object的一个synchronized(this)同步代码块时，另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。</p>
<p>package ths;</p>
<p>public class Thread2 { <br />
public void m4t1() { <br />
synchronized(this) { <br />
int i = 5; <br />
while( i-- &gt; 0) { <br />
System.out.println(Thread.currentThread().getName() + " : " + i); <br />
try { <br />
Thread.sleep(500); <br />
} catch (InterruptedException ie) { <br />
} <br />
} <br />
} <br />
} <br />
public void m4t2() { <br />
int i = 5; <br />
while( i-- &gt; 0) { <br />
System.out.println(Thread.currentThread().getName() + " : " + i); <br />
try { <br />
Thread.sleep(500); <br />
} catch (InterruptedException ie) { <br />
} <br />
} <br />
} <br />
public static void main(String[] args) { <br />
final Thread2 myt2 = new Thread2(); <br />
Thread t1 = new Thread( <br />
new Runnable() { <br />
public void run() { <br />
myt2.m4t1(); <br />
} <br />
}, "t1" <br />
); <br />
Thread t2 = new Thread( <br />
new Runnable() { <br />
public void run() { <br />
myt2.m4t2(); <br />
} <br />
}, "t2" <br />
); <br />
t1.start(); <br />
t2.start(); <br />
} <br />
}</p>
<p>结果：</p>
<p>t1 : 4 <br />
t2 : 4 <br />
t1 : 3 <br />
t2 : 3 <br />
t1 : 2 <br />
t2 : 2 <br />
t1 : 1 <br />
t2 : 1 <br />
t1 : 0 <br />
t2 : 0</p>
<p>三、尤其关键的是，当一个线程访问object的一个synchronized(this)同步代码块时，其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。</p>
<p>//修改Thread2.m4t2()方法：</p>
<p>public void m4t2() { <br />
synchronized(this) { <br />
int i = 5; <br />
while( i-- &gt; 0) { <br />
System.out.println(Thread.currentThread().getName() + " : " + i); <br />
try { <br />
Thread.sleep(500); <br />
} catch (InterruptedException ie) { <br />
} <br />
} <br />
}</p>
<p>}</p>
<p>结果：</p>
<p>t1 : 4 <br />
t1 : 3 <br />
t1 : 2 <br />
t1 : 1 <br />
t1 : 0 <br />
t2 : 4 <br />
t2 : 3 <br />
t2 : 2 <br />
t2 : 1 <br />
t2 : 0</p>
<p>四、第三个例子同样适用其它同步代码块。也就是说，当一个线程访问object的一个synchronized(this)同步代码块时，它就获得了这个object的对象锁。结果，其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。</p>
<p>//修改Thread2.m4t2()方法如下：</p>
<p>public synchronized void m4t2() { <br />
int i = 5; <br />
while( i-- &gt; 0) { <br />
System.out.println(Thread.currentThread().getName() + " : " + i); <br />
try { <br />
Thread.sleep(500); <br />
} catch (InterruptedException ie) { <br />
} <br />
} <br />
}</p>
<p>结果：</p>
<p>t1 : 4 <br />
t1 : 3 <br />
t1 : 2 <br />
t1 : 1 <br />
t1 : 0 <br />
t2 : 4 <br />
t2 : 3 <br />
t2 : 2 <br />
t2 : 1 <br />
t2 : 0</p>
<p>五、以上规则对其它对象锁同样适用:</p>
<p>package ths;</p>
<p>public class Thread3 { <br />
class Inner { <br />
private void m4t1() { <br />
int i = 5; <br />
while(i-- &gt; 0) { <br />
System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i); <br />
try { <br />
Thread.sleep(500); <br />
} catch(InterruptedException ie) { <br />
} <br />
} <br />
} <br />
private void m4t2() { <br />
int i = 5; <br />
while(i-- &gt; 0) { <br />
System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i); <br />
try { <br />
Thread.sleep(500); <br />
} catch(InterruptedException ie) { <br />
} <br />
} <br />
} <br />
} <br />
private void m4t1(Inner inner) { <br />
synchronized(inner) { //使用对象锁 <br />
inner.m4t1(); <br />
} <br />
} <br />
private void m4t2(Inner inner) { <br />
inner.m4t2(); <br />
} <br />
public static void main(String[] args) { <br />
final Thread3 myt3 = new Thread3(); <br />
final Inner inner = myt3.new Inner(); <br />
Thread t1 = new Thread( <br />
new Runnable() { <br />
public void run() { <br />
myt3.m4t1(inner); <br />
} <br />
}, "t1" <br />
); <br />
Thread t2 = new Thread( <br />
new Runnable() { <br />
public void run() { <br />
myt3.m4t2(inner); <br />
} <br />
}, "t2" <br />
); <br />
t1.start(); <br />
t2.start(); <br />
} <br />
}</p>
<p>结果：</p>
<p>尽管线程t1获得了对Inner的对象锁，但由于线程t2访问的是同一个Inner中的非同步部分。所以两个线程互不干扰。</p>
<p>t1 : Inner.m4t1()=4 <br />
t2 : Inner.m4t2()=4 <br />
t1 : Inner.m4t1()=3 <br />
t2 : Inner.m4t2()=3 <br />
t1 : Inner.m4t1()=2 <br />
t2 : Inner.m4t2()=2 <br />
t1 : Inner.m4t1()=1 <br />
t2 : Inner.m4t2()=1 <br />
t1 : Inner.m4t1()=0 <br />
t2 : Inner.m4t2()=0</p>
<p>现在在Inner.m4t2()前面加上synchronized：</p>
<p>private synchronized void m4t2() { <br />
int i = 5; <br />
while(i-- &gt; 0) { <br />
System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i); <br />
try { <br />
Thread.sleep(500); <br />
} catch(InterruptedException ie) { <br />
} <br />
} <br />
}</p>
<p>结果：</p>
<p>尽管线程t1与t2访问了同一个Inner对象中两个毫不相关的部分,但因为t1先获得了对Inner的对象锁，所以t2对Inner.m4t2()的访问也被阻塞，因为m4t2()是Inner中的一个同步方法。</p>
<p>t1 : Inner.m4t1()=4 <br />
t1 : Inner.m4t1()=3 <br />
t1 : Inner.m4t1()=2 <br />
t1 : Inner.m4t1()=1 <br />
t1 : Inner.m4t1()=0 <br />
t2 : Inner.m4t2()=4 <br />
t2 : Inner.m4t2()=3 <br />
t2 : Inner.m4t2()=2 <br />
t2 : Inner.m4t2()=1 <br />
t2 : Inner.m4t2()=0</p>
<img src ="http://www.blogjava.net/yc1354/aggbug/153179.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yc1354/" target="_blank">赵永超</a> 2007-10-16 10:43 <a href="http://www.blogjava.net/yc1354/archive/2007/10/16/153179.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java反射机制 (转)</title><link>http://www.blogjava.net/yc1354/archive/2007/06/14/124347.html</link><dc:creator>赵永超</dc:creator><author>赵永超</author><pubDate>Thu, 14 Jun 2007 08:52:00 GMT</pubDate><guid>http://www.blogjava.net/yc1354/archive/2007/06/14/124347.html</guid><wfw:comment>http://www.blogjava.net/yc1354/comments/124347.html</wfw:comment><comments>http://www.blogjava.net/yc1354/archive/2007/06/14/124347.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yc1354/comments/commentRss/124347.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yc1354/services/trackbacks/124347.html</trackback:ping><description><![CDATA[<p>摘要<br>Reflection 是Java被视为动态（或准动态）语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息，包括其modifiers（诸如public, static 等等）、superclass（例如Object）、实现之interfaces（例如Cloneable），也包括fields和methods的所有信息，并可于运行时改变fields内容或唤起methods。本文借由实例，大面积示范Reflection APIs。<br>&nbsp;<br>关键词：<br>Introspection（内省、内观）<br>Reflection（反射）<br>有时候我们说某个语言具有很强的动态性，有时候我们会区分动态和静态的不同技术与作法。我们朗朗上口动态绑定（dynamic binding）、动态链接（dynamic linking）、动态加载（dynamic loading）等。然而&#8220;动态&#8221;一词其实没有绝对而普遍适用的严格定义，有时候甚至像对象导向当初被导入编程领域一样，一人一把号，各吹各的调。<br>&nbsp;<br>一般而言，开发者社群说到动态语言，大致认同的一个定义是：&#8220;程序运行时，允许改变程序结构或变量类型，这种语言称为动态语言&#8221;。从这个观点看，Perl，Python，Ruby是动态语言，C++，Java，C#不是动态语言。<br>&nbsp;<br>尽管在这样的定义与分类下Java不是动态语言，它却有着一个非常突出的动态相关机制：Reflection。这个字的意思是&#8220;反射、映象、倒影&#8221;，用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说，Java程序可以加载一个运行时才得知名称的class，获悉其完整构造（但不包括methods定义），并生成其对象实体、或对其fields设值、或唤起其methods1。这种&#8220;看透class&#8221;的能力（the ability of the program to examine itself）被称为introspection（内省、内观、反省）。Reflection和introspection是常被并提的两个术语。<br>&nbsp;<br>Java如何能够做出上述的动态特性呢？这是一个深远话题，本文对此只简单介绍一些概念。整个篇幅最主要还是介绍Reflection APIs，也就是让读者知道如何探索class的结构、如何对某个&#8220;运行时才获知名称的class&#8221;生成一份实体、为其fields设值、调用其methods。本文将谈到java.lang.Class，以及java.lang.reflect中的Method、Field、Constructor等等classes。<br>&nbsp;<br>&#8220;Class&#8221;class<br>众所周知Java有个Object class，是所有Java classes的继承根源，其内声明了数个应该在所有Java class中被改写的methods：hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class object。<br>&nbsp;<br>Class class十分特殊。它和一般classes一样继承自Object，其实体用以表达Java程序运行时的classes和interfaces，也用来表达enum、array、primitive Java types（boolean, byte, char, short, int, long, float, double）以及关键词void。当一个class被加载，或当加载器（class loader）的defineClass()被JVM调用，JVM 便自动产生一个Class object。如果您想借由&#8220;修改Java标准库源码&#8221;来观察Class object的实际生成时机（例如在Class的constructor内添加一个println()），不能够！因为Class并没有public constructor（见图1）。本文最后我会拨一小块篇幅顺带谈谈Java标准库源码的改动办法。<br>&nbsp;<br>Class是Reflection故事起源。针对任何您想探勘的class，唯有先为它产生一个Class object，接下来才能经由后者唤起为数十多个的Reflection APIs。这些APIs将在稍后的探险活动中一一亮相。<br>&nbsp;<br>#001 public final<br>#002 class Class&lt;T&gt; implements java.io.Serializable,<br>#003 java.lang.reflect.GenericDeclaration,<br>#004 java.lang.reflect.Type,<br>#005 java.lang.reflect.AnnotatedElement {<br>#006&nbsp;&nbsp;&nbsp; private Class() {}<br>#007&nbsp;&nbsp;&nbsp; public String toString() {<br>#008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ( isInterface() ? "interface " :<br>#009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (isPrimitive() ? "" : "class "))<br>#010&nbsp;&nbsp;&nbsp; + getName();<br>#011 }<br>...<br>图1：Class class片段。注意它的private empty ctor，意指不允许任何人经由编程方式产生Class object。是的，其object 只能由JVM 产生。<br>&nbsp;<br>&#8220;Class&#8221; object的取得途径<br>Java允许我们从多种管道为一个class生成对应的Class object。图2是一份整理。<br>Class object 诞生管道 示例 <br>运用getClass()<br>注：每个class 都有此函数 String str = "abc";<br>Class c1 = str.getClass(); <br>运用<br>Class.getSuperclass()2 Button b = new Button();<br>Class c1 = b.getClass();<br>Class c2 = c1.getSuperclass(); <br>运用static method<br>Class.forName()<br>（最常被使用） Class c1 = Class.forName ("java.lang.String");<br>Class c2 = Class.forName ("java.awt.Button");<br>Class c3 = Class.forName ("java.util.LinkedList$Entry");<br>Class c4 = Class.forName ("I");<br>Class c5 = Class.forName ("[I"); <br>运用<br>.class 语法 Class c1 = String.class;<br>Class c2 = java.awt.Button.class;<br>Class c3 = Main.InnerClass.class;<br>Class c4 = int.class;<br>Class c5 = int[].class; <br>运用<br>primitive wrapper classes<br>的TYPE 语法<br>&nbsp; Class c1 = Boolean.TYPE;<br>Class c2 = Byte.TYPE;<br>Class c3 = Character.TYPE;<br>Class c4 = Short.TYPE;<br>Class c5 = Integer.TYPE;<br>Class c6 = Long.TYPE;<br>Class c7 = Float.TYPE;<br>Class c8 = Double.TYPE;<br>Class c9 = Void.TYPE; </p>
<p><br>图2：Java 允许多种管道生成Class object。<br>&nbsp;<br>Java classes 组成分析<br>首先容我以图3的java.util.LinkedList为例，将Java class的定义大卸八块，每一块分别对应图4所示的Reflection API。图5则是&#8220;获得class各区块信息&#8221;的程序示例及执行结果，它们都取自本文示例程序的对应片段。<br>&nbsp;<br>package java.util;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(1)<br>import java.lang.*;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(2)<br>public class LinkedList&lt;E&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(3)(4)(5)<br>extends AbstractSequentialList&lt;E&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(6)<br>implements List&lt;E&gt;, Queue&lt;E&gt;,<br>Cloneable, java.io.Serializable&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(7)<br>{<br>private static class Entry&lt;E&gt; { &#8230; }//(8)<br>public LinkedList() { &#8230; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(9)<br>public LinkedList(Collection&lt;? extends E&gt; c) { &#8230; }<br>public E getFirst() { &#8230; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //(10)<br>public E getLast() { &#8230; }<br>private transient Entry&lt;E&gt; header = &#8230;; //(11)<br>private transient int size = 0;<br>}<br>图3：将一个Java class 大卸八块，每块相应于一个或一组Reflection APIs（图4）。<br>&nbsp;<br>Java classes 各成份所对应的Reflection APIs<br>图3的各个Java class成份，分别对应于图4的Reflection API，其中出现的Package、Method、Constructor、Field等等classes，都定义于java.lang.reflect。<br>Java class 内部模块（参见图3） Java class 内部模块说明 相应之Reflection API，多半为Class methods。 返回值类型(return type) <br>(1) package class隶属哪个package getPackage() Package <br>(2) import class导入哪些classes 无直接对应之API。<br>解决办法见图5-2。&nbsp;&nbsp; <br>(3) modifier class（或methods, fields）的属性<br>&nbsp; int getModifiers()<br>Modifier.toString(int)<br>Modifier.isInterface(int) int<br>String<br>bool <br>(4) class name or interface name class/interface 名称getName() String <br>(5) type parameters 参数化类型的名称 getTypeParameters()&nbsp; TypeVariable &lt;Class&gt;[] <br>(6) base class base class（只可能一个） getSuperClass() Class <br>(7) implemented interfaces 实现有哪些interfaces getInterfaces() Class[]<br>&nbsp; <br>(8) inner classes 内部classes getDeclaredClasses() Class[] <br>(8') outer class 如果我们观察的class 本身是inner classes，那么相对它就会有个outer class。 getDeclaringClass() Class <br>(9) constructors 构造函数getDeclaredConstructors() 不论 public 或private 或其它access level，皆可获得。另有功能近似之取得函数。 Constructor[] <br>(10) methods 操作函数getDeclaredMethods() 不论 public 或private 或其它access level，皆可获得。另有功能近似之取得函数。 Method[] <br>(11) fields 字段（成员变量） getDeclaredFields()不论 public 或private 或其它access level，皆可获得。另有功能近似之取得函数。 Field[] </p>
<p><br>图4：Java class大卸八块后（如图3），每一块所对应的Reflection API。本表并非<br>Reflection APIs 的全部。<br>&nbsp;<br>Java Reflection API 运用示例<br>图5示范图4提过的每一个Reflection API，及其执行结果。程序中出现的tName()是个辅助函数，可将其第一自变量所代表的&#8220;Java class完整路径字符串&#8221;剥除路径部分，留下class名称，储存到第二自变量所代表的一个hashtable去并返回（如果第二自变量为null，就不储存而只是返回）。<br>&nbsp;<br>#001 Class c = null;<br>#002 c = Class.forName(args[0]);<br>#003<br>#004 Package p;<br>#005 p = c.getPackage();<br>#006<br>#007 if (p != null)<br>#008&nbsp;&nbsp;&nbsp; System.out.println("package "+p.getName()+";");<br>&nbsp;<br>执行结果（例）：<br>package java.util;<br>图5-1：找出class 隶属的package。其中的c将继续沿用于以下各程序片段。<br>&nbsp;<br>#001 ff = c.getDeclaredFields();<br>#002 for (int i = 0; i &lt; ff.length; i++)<br>#003&nbsp;&nbsp;&nbsp; x = tName(ff[i].getType().getName(), classRef);<br>#004<br>#005 cn = c.getDeclaredConstructors();<br>#006 for (int i = 0; i &lt; cn.length; i++) {<br>#007&nbsp;&nbsp;&nbsp; Class cx[] = cn[i].getParameterTypes();<br>#008&nbsp;&nbsp;&nbsp; for (int j = 0; j &lt; cx.length; j++)<br>#009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x = tName(cx[j].getName(), classRef);<br>#010 }<br>#011<br>#012 mm = c.getDeclaredMethods();<br>#013 for (int i = 0; i &lt; mm.length; i++) {<br>#014&nbsp;&nbsp;&nbsp; x = tName(mm[i].getReturnType().getName(), classRef);<br>#015&nbsp;&nbsp;&nbsp; Class cx[] = mm[i].getParameterTypes();<br>#016&nbsp;&nbsp;&nbsp; for (int j = 0; j &lt; cx.length; j++)<br>#017&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x = tName(cx[j].getName(), classRef);<br>#018 }<br>#019 classRef.remove(c.getName()); //不必记录自己（不需import 自己）<br>&nbsp;<br>执行结果（例）：<br>import java.util.ListIterator;<br>import java.lang.Object;<br>import java.util.LinkedList$Entry;<br>import java.util.Collection;<br>import java.io.ObjectOutputStream;<br>import java.io.ObjectInputStream;<br>图5-2：找出导入的classes，动作细节详见内文说明。<br>&nbsp;<br>#001 int mod = c.getModifiers();<br>#002 System.out.print(Modifier.toString(mod)); //整个modifier<br>#003<br>#004 if (Modifier.isInterface(mod))<br>#005&nbsp;&nbsp;&nbsp; System.out.print(" "); //关键词 "interface" 已含于modifier<br>#006 else<br>#007&nbsp;&nbsp;&nbsp; System.out.print(" class "); //关键词 "class"<br>#008 System.out.print(tName(c.getName(), null)); //class 名称<br>&nbsp;<br>执行结果（例）：<br>public class LinkedList<br>图5-3：找出class或interface 的名称，及其属性（modifiers）。<br>&nbsp;<br>#001 TypeVariable&lt;Class&gt;[] tv;<br>#002 tv = c.getTypeParameters(); //warning: unchecked conversion<br>#003 for (int i = 0; i &lt; tv.length; i++) {<br>#004&nbsp;&nbsp;&nbsp; x = tName(tv[i].getName(), null); //例如 E,K,V...<br>#005&nbsp;&nbsp;&nbsp; if (i == 0) //第一个<br>#006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("&lt;" + x);<br>#007&nbsp;&nbsp;&nbsp; else //非第一个<br>#008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print("," + x);<br>#009&nbsp;&nbsp;&nbsp; if (i == tv.length-1) //最后一个<br>#010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("&gt;");<br>#011 }<br>&nbsp;<br>执行结果（例）：<br>public abstract interface Map&lt;K,V&gt;<br>或public class LinkedList&lt;E&gt;<br>图5-4：找出parameterized types 的名称<br>&nbsp;<br>#001 Class supClass;<br>#002 supClass = c.getSuperclass();<br>#003 if (supClass != null) //如果有super class<br>#004&nbsp;&nbsp;&nbsp; System.out.print(" extends" +<br>#005 tName(supClass.getName(),classRef));<br>&nbsp;<br>执行结果（例）：<br>public class LinkedList&lt;E&gt;<br>extends AbstractSequentialList,<br>图5-5：找出base class。执行结果多出一个不该有的逗号于尾端。此非本处重点，为简化计，不多做处理。<br>&nbsp;<br>#001 Class cc[];<br>#002 Class ctmp;<br>#003 //找出所有被实现的interfaces<br>#004 cc = c.getInterfaces();<br>#005 if (cc.length != 0)<br>#006&nbsp;&nbsp;&nbsp; System.out.print(", \r\n" + " implements "); //关键词<br>#007 for (Class cite : cc) //JDK1.5 新式循环写法<br>#008&nbsp;&nbsp;&nbsp; System.out.print(tName(cite.getName(), null)+", ");<br>&nbsp;<br>执行结果（例）：<br>public class LinkedList&lt;E&gt;<br>extends AbstractSequentialList,<br>implements List, Queue, Cloneable, Serializable,<br>图5-6：找出implemented interfaces。执行结果多出一个不该有的逗号于尾端。此非本处重点，为简化计，不多做处理。<br>&nbsp;<br>#001 cc = c.getDeclaredClasses(); //找出inner classes<br>#002 for (Class cite : cc)<br>#003&nbsp;&nbsp;&nbsp; System.out.println(tName(cite.getName(), null));<br>#004<br>#005 ctmp = c.getDeclaringClass(); //找出outer classes<br>#006 if (ctmp != null)<br>#007&nbsp;&nbsp;&nbsp; System.out.println(ctmp.getName());<br>&nbsp;<br>执行结果（例）：<br>LinkedList$Entry<br>LinkedList$ListItr<br>图5-7：找出inner classes 和outer class<br>&nbsp;<br>#001 Constructor cn[];<br>#002 cn = c.getDeclaredConstructors();<br>#003 for (int i = 0; i &lt; cn.length; i++) {<br>#004&nbsp;&nbsp;&nbsp; int md = cn[i].getModifiers();<br>#005&nbsp;&nbsp;&nbsp; System.out.print(" " + Modifier.toString(md) + " " +<br>#006&nbsp;&nbsp;&nbsp; cn[i].getName());<br>#007&nbsp;&nbsp;&nbsp; Class cx[] = cn[i].getParameterTypes();<br>#008&nbsp;&nbsp;&nbsp; System.out.print("(");<br>#009&nbsp;&nbsp;&nbsp; for (int j = 0; j &lt; cx.length; j++) {<br>#010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(tName(cx[j].getName(), null));<br>#011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (j &lt; (cx.length - 1)) System.out.print(", ");<br>#012&nbsp;&nbsp;&nbsp; }<br>#013&nbsp;&nbsp;&nbsp; System.out.print(")");<br>#014 }<br>&nbsp;<br>执行结果（例）：<br>public java.util.LinkedList(Collection)<br>public java.util.LinkedList()<br>图5-8a：找出所有constructors<br>&nbsp;<br>#004 System.out.println(cn[i].toGenericString());<br>&nbsp;<br>执行结果（例）：<br>public java.util.LinkedList(java.util.Collection&lt;? extends E&gt;)<br>public java.util.LinkedList()<br>图5-8b：找出所有constructors。本例在for 循环内使用toGenericString()，省事。<br>&nbsp;<br>#001 Method mm[];<br>#002 mm = c.getDeclaredMethods();<br>#003 for (int i = 0; i &lt; mm.length; i++) {<br>#004&nbsp;&nbsp;&nbsp; int md = mm[i].getModifiers();<br>#005&nbsp;&nbsp;&nbsp; System.out.print(" "+Modifier.toString(md)+" "+<br>#006&nbsp;&nbsp;&nbsp; tName(mm[i].getReturnType().getName(), null)+" "+<br>#007&nbsp;&nbsp;&nbsp; mm[i].getName());<br>#008&nbsp;&nbsp;&nbsp; Class cx[] = mm[i].getParameterTypes();<br>#009&nbsp;&nbsp;&nbsp; System.out.print("(");<br>#010&nbsp;&nbsp;&nbsp; for (int j = 0; j &lt; cx.length; j++) {<br>#011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(tName(cx[j].getName(), null));<br>#012&nbsp;&nbsp;&nbsp; if (j &lt; (cx.length - 1)) System.out.print(", ");<br>#013&nbsp;&nbsp;&nbsp; }<br>#014&nbsp;&nbsp;&nbsp; System.out.print(")");<br>#015 }<br>&nbsp;<br>执行结果（例）：<br>public Object get(int)<br>public int size()<br>图5-9a：找出所有methods<br>&nbsp;<br>#004 System.out.println(mm[i].toGenericString());<br>&nbsp;<br>public E java.util.LinkedList.get(int)<br>public int java.util.LinkedList.size()<br>图5-9b：找出所有methods。本例在for 循环内使用toGenericString()，省事。<br>&nbsp;<br>#001 Field ff[];<br>#002 ff = c.getDeclaredFields();<br>#003 for (int i = 0; i &lt; ff.length; i++) {<br>#004&nbsp;&nbsp;&nbsp; int md = ff[i].getModifiers();<br>#005&nbsp;&nbsp;&nbsp; System.out.println(" "+Modifier.toString(md)+" "+<br>#006&nbsp;&nbsp;&nbsp; tName(ff[i].getType().getName(), null) +" "+<br>#007&nbsp;&nbsp;&nbsp; ff[i].getName()+";");<br>#008 }<br>&nbsp;<br>执行结果（例）：<br>private transient LinkedList$Entry header;<br>private transient int size;<br>图5-10a：找出所有fields<br>&nbsp;<br>#004 System.out.println("G: " + ff[i].toGenericString());<br>&nbsp;<br>private transient java.util.LinkedList.java.util.LinkedList$Entry&lt;E&gt; ??<br>java.util.LinkedList.header<br>private transient int java.util.LinkedList.size<br>图5-10b：找出所有fields。本例在for 循环内使用toGenericString()，省事。<br>&nbsp;<br>找出class参用（导入）的所有classes<br>没有直接可用的Reflection API可以为我们找出某个class参用的所有其它classes。要获得这项信息，必须做苦工，一步一脚印逐一记录。我们必须观察所有fields的类型、所有methods（包括constructors）的参数类型和回返类型，剔除重复，留下唯一。这正是为什么图5-2程序代码要为tName()指定一个hashtable（而非一个null）做为第二自变量的缘故：hashtable可为我们储存元素（本例为字符串），又保证不重复。<br>&nbsp;<br>本文讨论至此，几乎可以还原一个class的原貌（唯有methods 和ctors的定义无法取得）。接下来讨论Reflection 的另三个动态性质：(1) 运行时生成instances，(2) 执<br>行期唤起methods，(3) 运行时改动fields。<br>&nbsp;<br>运行时生成instances<br>欲生成对象实体，在Reflection 动态机制中有两种作法，一个针对&#8220;无自变量ctor&#8221;，<br>一个针对&#8220;带参数ctor&#8221;。图6是面对&#8220;无自变量ctor&#8221;的例子。如果欲调用的是&#8220;带参数ctor&#8220;就比较麻烦些，图7是个例子，其中不再调用Class的newInstance()，而是调用Constructor 的newInstance()。图7首先准备一个Class[]做为ctor的参数类型（本例指定为一个double和一个int），然后以此为自变量调用getConstructor()，获得一个专属ctor。接下来再准备一个Object[] 做为ctor实参值（本例指定3.14159和125），调用上述专属ctor的newInstance()。<br>&nbsp;<br>#001 Class c = Class.forName("DynTest");<br>#002 Object obj = null;<br>#003 obj = c.newInstance(); //不带自变量<br>#004 System.out.println(obj);<br>图6：动态生成&#8220;Class object 所对应之class&#8221;的对象实体；无自变量。<br>&nbsp;<br>#001 Class c = Class.forName("DynTest");<br>#002 Class[] pTypes = new Class[] { double.class, int.class };<br>#003 Constructor ctor = c.getConstructor(pTypes);<br>#004 //指定parameter list，便可获得特定之ctor<br>#005<br>#006 Object obj = null;<br>#007 Object[] arg = new Object[] {3.14159, 125}; //自变量<br>#008 obj = ctor.newInstance(arg);<br>#009 System.out.println(obj);<br>图7：动态生成&#8220;Class object 对应之class&#8221;的对象实体；自变量以Object[]表示。<br>&nbsp;<br>运行时调用methods<br>这个动作和上述调用&#8220;带参数之ctor&#8221;相当类似。首先准备一个Class[]做为ctor的参数类型（本例指定其中一个是String，另一个是Hashtable），然后以此为自变量调用getMethod()，获得特定的Method object。接下来准备一个Object[]放置自变量，然后调用上述所得之特定Method object的invoke()，如图8。知道为什么索取Method object时不需指定回返类型吗？因为method overloading机制要求signature（署名式）必须唯一，而回返类型并非signature的一个成份。换句话说，只要指定了method名称和参数列，就一定指出了一个独一无二的method。<br>&nbsp;<br>#001 public String func(String s, Hashtable ht)<br>#002 {<br>#003 &#8230;System.out.println("func invoked"); return s;<br>#004 }<br>#005 public static void main(String args[])<br>#006 {<br>#007 Class c = Class.forName("Test");<br>#008 Class ptypes[] = new Class[2];<br>#009 ptypes[0] = Class.forName("java.lang.String");<br>#010 ptypes[1] = Class.forName("java.util.Hashtable");<br>#011 Method m = c.getMethod("func",ptypes);<br>#012 Test obj = new Test();<br>#013 Object args[] = new Object[2];<br>#014 arg[0] = new String("Hello,world");<br>#015 arg[1] = null;<br>#016 Object r = m.invoke(obj, arg);<br>#017 Integer rval = (String)r;<br>#018 System.out.println(rval);<br>#019 }<br>图8：动态唤起method<br>&nbsp;<br>运行时变更fields内容<br>与先前两个动作相比，&#8220;变更field内容&#8221;轻松多了，因为它不需要参数和自变量。首先调用Class的getField()并指定field名称。获得特定的Field object之后便可直接调用Field的get()和set()，如图9。<br>&nbsp;<br>#001 public class Test {<br>#002 public double d;<br>#003<br>#004 public static void main(String args[])<br>#005 {<br>#006 Class c = Class.forName("Test");<br>#007 Field f = c.getField("d"); //指定field 名称<br>#008 Test obj = new Test();<br>#009 System.out.println("d= " + (Double)f.get(obj));<br>#010 f.set(obj, 12.34);<br>#011 System.out.println("d= " + obj.d);<br>#012 }<br>#013 }<br>图9：动态变更field 内容<br>&nbsp;<br>Java 源码改动办法<br>先前我曾提到，原本想借由&#8220;改动Java标准库源码&#8221;来测知Class object的生成，但由于其ctor原始设计为private，也就是说不可能透过这个管道生成Class object（而是由class loader负责生成），因此&#8220;在ctor中打印出某种信息&#8221;的企图也就失去了意义。<br>&nbsp;<br>这里我要谈点题外话：如何修改Java标准库源码并让它反应到我们的应用程序来。假设我想修改java.lang.Class，让它在某些情况下打印某种信息。首先必须找出标准源码！当你下载JDK 套件并安装妥当，你会发现jdk150\src\java\lang 目录（见图10）之中有Class.java，这就是我们此次行动的标准源码。备份后加以修改，编译获得Class.class。接下来准备将.class 搬移到jdk150\jre\lib\endorsed（见图10）。<br>&nbsp;<br>这是一个十分特别的目录，class loader将优先从该处读取内含classes的.jar文件——成功的条件是.jar内的classes压缩路径必须和Java标准库的路径完全相同。为此，我们可以将刚才做出的Class.class先搬到一个为此目的而刻意做出来的\java\lang目录中，压缩为foo.zip（任意命名，唯需夹带路径java\lang），再将这个foo.zip搬到jdk150\jre\lib\endorsed并改名为foo.jar。此后你的应用程序便会优先用上这里的java.lang.Class。整个过程可写成一个批处理文件（batch file），如图11，在DOS Box中使用。<br>&nbsp;<br>&nbsp;<br>图10：JDK1.5 安装后的目录组织。其中的endorsed 是我新建。<br>&nbsp;<br>del e:\java\lang\*.class //清理干净<br>del c:\jdk150\jre\lib\endorsed\foo.jar //清理干净<br>c:<br>cd c:\jdk150\src\java\lang<br>javac -Xlint:unchecked Class.java //编译源码<br>javac -Xlint:unchecked ClassLoader.java //编译另一个源码（如有必要）<br>move *.class e:\java\lang //搬移至刻意制造的目录中<br>e:<br>cd e:\java\lang //以下压缩至适当目录<br>pkzipc -add -path=root c:\jdk150\jre\lib\endorsed\foo.jar *.class<br>cd e:\test //进入测试目录<br>javac -Xlint:unchecked Test.java //编译测试程序<br>java Test //执行测试程序<br>图11：一个可在DOS Box中使用的批处理文件（batch file），用以自动化java.lang.Class<br>的修改动作。Pkzipc(.exe)是个命令列压缩工具，add和path都是其命令。<br>&nbsp;<br>更多信息<br>以下是视野所及与本文主题相关的更多讨论。这些信息可以弥补因文章篇幅限制而带来的不足，或带给您更多视野。<br>&nbsp;<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Take an in-depth look at the Java Reflection API -- Learn about the new Java 1.1 tools forfinding out information about classes", by Chuck McManis。此篇文章所附程序代码是本文示例程序的主要依据（本文示例程序示范了更多Reflection APIs，并采用JDK1.5 新式的for-loop 写法）。<br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br></p>
<img src ="http://www.blogjava.net/yc1354/aggbug/124347.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yc1354/" target="_blank">赵永超</a> 2007-06-14 16:52 <a href="http://www.blogjava.net/yc1354/archive/2007/06/14/124347.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java1.5语言新特性简单总结(转)</title><link>http://www.blogjava.net/yc1354/archive/2007/06/14/124320.html</link><dc:creator>赵永超</dc:creator><author>赵永超</author><pubDate>Thu, 14 Jun 2007 06:38:00 GMT</pubDate><guid>http://www.blogjava.net/yc1354/archive/2007/06/14/124320.html</guid><wfw:comment>http://www.blogjava.net/yc1354/comments/124320.html</wfw:comment><comments>http://www.blogjava.net/yc1354/archive/2007/06/14/124320.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yc1354/comments/commentRss/124320.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yc1354/services/trackbacks/124320.html</trackback:ping><description><![CDATA[<div class=postText><font color=#333333><strong>1. 自动装箱与拆箱 对应C#<br></strong>　　<br>　　例1.1<br>　　Integer i = 10;<br>　　int j = i;<br>　　<br>　　<strong>2. 更优化的for循环 对应就C#---foreach循环</strong><br>　　<br>　　例2.1<br>　　String[] names = {"BadBoy","GoodBoy","HappyGirl","sadGirl"};<br>　　for(String option: names) {<br>　　System.out.println(option);<br>　　}<br>　　<br>　　例2.2 加泛型 对应C++模板<br>　　import java.util.*;<br>　　<br>　　ArrayList&lt;String&gt; animals = new ArrayList&lt;String&gt;();<br>　　animals.add("Dog");<br>　　animals.add("Cat");<br>　　animals.add("Chick");<br>　　animals.add("Cow");<br>　　for(String option : animals) {<br>　　System.out.println(option);<br>　　}<br>　　<br>　　<strong>3.参数可变的方法和printf</strong><br>　　<br>　　例3.1<br>　　定义:<br>　　public int sum(int... n) {　//传过来n为一个int型数组<br>　　int tempSum;<br>　　for(int option : n) {<br>　　tempSum+=option;<br>　　}<br>　　/*<br>　　for(int i = 0; i &lt; n.length; i++) {<br>　　tempSum+=n[i];<br>　　}<br>　　*/<br>　　return tempSum;<br>　　}<br>　　调用1: sum(1);<br>　　调用2: sum(1,2);<br>　　调用3: sum(1,2,3,4);<br>　　<br>　　例3.2 printf方法,　对应c语言的printf<br>　　int x = 10;<br>　　int y = 20;<br>　　int sum = x + y;<br>　　System.out.printf("%d + %d = %d",x,y,sum);<br>　　<br>　　<strong>4. 枚举</strong><br>　　<br>　　例4.1<br>　　public enum MyColors {<br>　　red,<br>　　black,<br>　　blue,<br>　　green,<br>　　yellow<br>　　}<br>　　<br>　　MyColors color = MyColors.red;<br>　　for(MyColors option : color.values()) {<br>　　System.out.println(option);<br>　　}<br>　　<br>　　/**不能在switch语句里这样写case MyColors.red:<br>　　*这样编译器不会让你通过*/<br>　　switch(color) {<br>　　case red:<br>　　System.out.println("best color is "+red);<br>　　break;<br>　　case black:<br>　　System.out.println("NO " + black);<br>　　break;<br>　　default:<br>　　System.out.println("What");<br>　　break;<br>　　}<br>　　<br>　　<strong>5.静态引用</strong><br>　　<br>　　例5.1<br>　　1.5版本以前的写法是：<br>　　<br>　　import java.lang.Math; //程序开头处<br>　　<br>　　...<br>　　<br>　　double x = Math.random();<br>　　1.5版本中可以这样写<br>　　import static java.lang.Math.random; //程序开头处<br>　　<br>　　...<br>　　<br>　　double x = random();</font><br></div>
<img src ="http://www.blogjava.net/yc1354/aggbug/124320.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yc1354/" target="_blank">赵永超</a> 2007-06-14 14:38 <a href="http://www.blogjava.net/yc1354/archive/2007/06/14/124320.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>分隔字符串</title><link>http://www.blogjava.net/yc1354/archive/2007/03/26/106391.html</link><dc:creator>赵永超</dc:creator><author>赵永超</author><pubDate>Mon, 26 Mar 2007 06:12:00 GMT</pubDate><guid>http://www.blogjava.net/yc1354/archive/2007/03/26/106391.html</guid><wfw:comment>http://www.blogjava.net/yc1354/comments/106391.html</wfw:comment><comments>http://www.blogjava.net/yc1354/archive/2007/03/26/106391.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yc1354/comments/commentRss/106391.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yc1354/services/trackbacks/106391.html</trackback:ping><description><![CDATA[
		<p>import java.util.*;<br />public class TokenTest2{<br /> <br /> public static void main(String[] args){<br />  <br />  StringTokenizer st=new StringTokenizer("this is a test","e",true);<br />  while(st.hasMoreTokens()){<br />   System.out.println(st.nextToken());<br />   <br />  }<br /> }<br />}<br />结果 ：<br />this is a t<br />e<br />st<br /> <br />public class StringTokenizer</p>
		<p>extends Object <br />implements Enumeration&lt;Object&gt; <br />string tokenizer 类允许应用程序将字符串分解为标记。tokenization 方法比 StreamTokenizer 类所使用的方法更简单。StringTokenizer 方法不区分标识符、数和带引号的字符串，它们也不识别并跳过注释。</p>
		<p>可以在创建时指定，也可以根据每个标记来指定分隔符（分隔标记的字符）集合。</p>
		<p>StringTokenizer 的实例有两种行为方式，这取决于它在创建时使用的 returnDelims 标志的值是 true 还是 false：</p>
		<p>如果标志为 false，则分隔符字符用来分隔标记。标记是连续字符（不是分隔符）的最大序列。 <br />如果标志为 true，则认为那些分隔符字符本身即为标记。因此标记要么是一个分隔符字符，要么是那些连续字符（不是分隔符）的最大序列。 <br />StringTokenizer 对象在内部维护字符串中要被标记的当前位置。某些操作将此当前位置移至已处理的字符后。</p>
		<p>通过截取字符串的一个子串来返回标记，该字符串用于创建 StringTokenizer 对象。</p>
		<p>下面是一个使用 tokenizer 的实例。代码如下：</p>
		<p>     StringTokenizer st = new StringTokenizer("this is a test");<br />     while (st.hasMoreTokens()) {<br />         System.out.println(st.nextToken());<br />     }<br /> </p>
		<p>输出以下字符串：</p>
		<p>     this<br />     is<br />     a<br />     test<br /> </p>
		<p>StringTokenizer 是出于兼容性的原因而被保留的遗留类（虽然在新代码中并不鼓励使用它）。建议所有寻求此功能的人使用 String 的 split 方法或 java.util.regex 包。</p>
		<p>下面的示例阐明了如何使用 String.split 方法将字符串分解为基本标记：</p>
		<p>     String[] result = "this is a test".split("<a href="file://\\s">\\s</a>");<br />     for (int x=0; x&lt;result.length; x++)<br />         System.out.println(result[x]);<br /> </p>
		<p>输出以下字符串：</p>
		<p>     this<br />     is<br />     a<br />     test</p>
		<p> </p>
<img src ="http://www.blogjava.net/yc1354/aggbug/106391.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yc1354/" target="_blank">赵永超</a> 2007-03-26 14:12 <a href="http://www.blogjava.net/yc1354/archive/2007/03/26/106391.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>读取*.properties文件的方法</title><link>http://www.blogjava.net/yc1354/archive/2007/02/01/97261.html</link><dc:creator>赵永超</dc:creator><author>赵永超</author><pubDate>Thu, 01 Feb 2007 06:41:00 GMT</pubDate><guid>http://www.blogjava.net/yc1354/archive/2007/02/01/97261.html</guid><wfw:comment>http://www.blogjava.net/yc1354/comments/97261.html</wfw:comment><comments>http://www.blogjava.net/yc1354/archive/2007/02/01/97261.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yc1354/comments/commentRss/97261.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yc1354/services/trackbacks/97261.html</trackback:ping><description><![CDATA[
		<br />public class SysUtils{<br /><br />Properties property = new Properties();<br />InputStream is = null;<br />try{<br />is = SysUtils.class.getClassLoader().getResourceAsStream("system.properties");<br />property.load(is);<br />String s = property.getProperty("CMS_URL");<br />}catch(Excption e){<br />System.out.println("hi"):<br />}<br /><br /><br />}<img src ="http://www.blogjava.net/yc1354/aggbug/97261.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yc1354/" target="_blank">赵永超</a> 2007-02-01 14:41 <a href="http://www.blogjava.net/yc1354/archive/2007/02/01/97261.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>