?? java編程 的動態性,第 2部分:引入反射.htm
字號:
return timing.m_value;
} catch (Exception ex) {
System.out.println("Error using reflection");
throw ex;
}
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>測試程序重復調用每種方法,使用一個大循環數,從而平均多次調用的時間衡量結果。平均值中不包括每種方法第一次調用的時間,因此初始化時間不是結果中的一個因素。在為本文進行的測試中,
每次調用時我使用1000萬的循環數,在1GHz PIIIm系統上運行。三個不同Linux
JVM的計時結果如圖1所示。所有測試使用每個JVM的缺省設置。</P>
<P><A name=IDAT1MQD><B>圖 1:字段接入時間 </B></A><BR><IMG
alt="Field access times" height=238
src="Java編程 的動態性,第 2部分:引入反射.files/field-accesses.jpg" width=538></P>
<P>上表的對數尺度可以顯示所有時間,但減少了差異看得見的影響。在前兩副圖中(Sun
JVM),使用反射的執行時間超過使用直接接入的1000倍以上。通過比較,IBM
JVM可能稍好一些,但反射方法仍舊需要比其它方法長700倍以上的時間。任何JVM上其它兩種方法之間時間方面無任何顯著差異,但IBM
JVM幾乎比Sun JVM快一倍。最有可能的是這種差異反映了Sun Hot Spot JVM的專業優化,它在簡單基準方面表現得很糟糕。</P>
<P>除了字段接入時間測試之外,我還進行了相同的方法調用時間測試。在方法調用中,我試用了與字段接入相同的三種接入變量,并增加了使用無參數方法變量,而不是在方法調用中傳遞和返回一個值。清單8顯示了用于測試調用傳遞和返回值形式的三種方法的代碼。</P><A
name=IDAB2MQD><B>清單 8:方法接入性能測試代碼</B></A><BR>
<TABLE bgColor=#cccccc border=1 cellPadding=5 cellSpacing=0
width="100%"><TBODY>
<TR>
<TD><PRE><CODE>
public int callDirectArgs(int loops) {
int value = 0;
for (int index = 0; index < loops; index++) {
value = step(value);
}
return value;
}
public int callReferenceArgs(int loops) {
TimingClass timing = new TimingClass();
int value = 0;
for (int index = 0; index < loops; index++) {
value = timing.step(value);
}
return value;
}
public int callReflectArgs(int loops) throws Exception {
TimingClass timing = new TimingClass();
try {
Method method = TimingClass.class.getMethod
("step", new Class [] { int.class });
Object[] args = new Object[1];
Object value = new Integer(0);
for (int index = 0; index < loops; index++) {
args[0] = value;
value = method.invoke(timing, args);
}
return ((Integer)value).intValue();
} catch (Exception ex) {
System.out.println("Error using reflection");
throw ex;
}
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>圖 2顯示了我從方法調用中獲得的計時結果。反射遠慢于直接接入。差異不象字段接入那么大,但是,在不使用參數的情況下,范圍從Sun 1.3.1
JVM的數百倍到IBM
JVM的不到30倍。在所有JVM上,使用參數的反射方法調用的測試性能慢于不使用參數的調用。由于傳遞和返回<CODE>int</CODE>值需要的<CODE>java.lang.Integer</CODE>封裝,這可能是局部的。由于<CODE>Integer</CODE>s是不可變的,每種方法返回提出了一種新的需求,它將增加大量的開銷。</P>
<P><A name=IDA02MQD><B>圖 2:方法調用時間</B></A><BR><IMG alt="Method call times"
height=372 src="Java編程 的動態性,第 2部分:引入反射.files/method-calls.jpg"
width=561></P>
<P>反射性能是Sun開發1.4 JVM時關注的一個方面,它在反射方法調用結果中顯示。在這類操作的性能方面,Sun 1.4.1
JVM顯示了比1.3.1版本很大的改進,在我的測試中運行速度大約是1.3.1版本的開部。在這類簡單的測試中,IBM 1.4.0
JVM再次獲得了更好的成績,但是只比Sun 1.4.1 JVM快兩到三倍。</P>
<P>我還為創建使用反射的對象編寫了類似的計時測試程序,但這種情況下的差異不象字段和方法調用情況下那么顯著。使用<CODE>newInstance()</CODE>調用創建一個簡單的<CODE>java.lang.Object</CODE>實例耗用的時間大約是在Sun
1.3.1 JVM上使用<CODE>new Object()</CODE>的12倍,是在IBM 1.4.0 JVM的四倍,只是Sun 1.4.1
JVM上的兩部。使用<CODE>Array.newInstance(type,
size)</CODE>創建一個數組耗用的時間是任何測試的JVM上使用<CODE>new
type[size]</CODE>的兩倍,隨著數組大小的增加,差異逐步縮小。</P>
<P><A name=IDA33MQD><SPAN
class=atitle2>結束語</SPAN></A><BR>Java語言反射提供一種動態鏈接程序組件的多功能方法。它允許程序創建和控制任何類的對象(根據安全性限制),無需提前硬編碼目標類。這些特性使得反射特別適用于創建以非常普通的方式與對象協作的庫。例如,反射經常在持續存儲對象為數據庫、XML或其它外部格式的框架中使用。</P>
<P>反射有兩個缺點。第一個是性能問題。當用于字段和方法接入時反射要遠慢于直接代碼。性能問題的程度取決于程序中是如何使用反射的。如果它作為程序運行中相對很少涉及的部分,緩慢的性能將不會是一個問題。即使測試中最壞情況下的計時圖顯示的反射操作只耗用幾微秒。僅反射在性能關鍵的應用的核心邏輯中使用時性能問題才變得至關重要。</P>
<P>許多應用更嚴重的一個缺點是使用反射會模糊程序內部實際要發生的事情。程序人員希望在源代碼中看到程序的邏輯,反射等繞過了源代碼的技術會帶來維護問題。反射代碼比相應的直接代碼更復雜,正如性能比較的代碼實例中看到的一樣。解決這些問題的最佳方案是保守地使用反射--
僅在它可以真正增加靈活性的地方 -- 記錄其在目標類中的使用。</P>
<P>在下一部分,我將提供如何使用反射的更詳細實例。這種實例提供一個處理Java應用命令行參數的API,一種您可能發現適用于自己應用的工具。它還基于反射的優勢來創建,同時避免其弱點。反射是否能簡化您的命令行處理?您可以在<I>Java編程的動態性</I>第3部分找到答案。</P><!-- RESOURCES-->
<P><A name=resources><SPAN class=atitle2>參考資料</SPAN></A>
<UL><!-- Comment out list item below if there is no forum for this article-->
<LI>下載本文中使用的<A
href="ftp://www6.software.ibm.com/software/developer/library/j-dyn0603.zip">performance
benchmarks programs</A>。<BR><BR>
<LI>閱讀“<A
href="http://www-106.ibm.com/developerworks/java/library/j-reflection.html">Reflection:
A new way to discover information about Java classes</A>”
(<I>developerWorks</I>, 1998年5月),了解過去關于Java反射的增長功能的看法。<BR><BR>
<LI>反射在與JavaBeans組件協作中扮演了一個極其重要的角色。閱讀“<A
href="http://www-106.ibm.com/developerworks/java/library/j-introspect/">Reflecting,
introspecting, and customizing JavaBeans</A>”(<I>developerWorks</I>,
2000年2月)了解所有相關信息。<BR><BR>
<LI>反射的大范圍使用會影響框架的性能。關于圖形實例及一些相關討論,請參閱作者的XML數據捆綁文章“<A
href="http://www-900.ibm.com/developerWorks/cn/xml/x-databdopt/part2/index.shtml">\數據幫定,
第二部分: 性能</A>”(<I>developerWorks</I>,2003年1月)和“<A
href="http://www-900.ibm.com/developerWorks/cn/xml/x-databd3/index.shtml">數據綁定,第
3 部分:JiBX 體系結構</A>”(<I>developerWorks</I>,2003年4月)。<BR><BR>
<LI>關于使用反射的高級教程,請閱讀Sun提供的Java教程中的<A
href="http://java.sun.com/docs/books/tutorial/reflect/index.html">The
Reflection API</A>。<BR><BR>
<LI>在<A
href="http://www-900.ibm.com/developerWorks/cn/java/index.shtml"><I>developerWorks</I>
Java技術專區</A>中可以找到數百篇關于Java技術的文章。<BR><BR></LI></UL>
<P></P><!-- AUTHOR BIOS--><!-- Make author heading singular or plural as needed-->
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD><A name=author1><SPAN class=atitle2>關于作者</SPAN></A> <BR><IMG
align=left alt="Photo of Dennis Sosnoski" border=0 height=80
src="Java編程 的動態性,第 2部分:引入反射.files/p-sosnoski.jpg" width=64>Dennis
Sosnoski 是西雅圖地區 Java 咨詢公司 <A href="http://www.sosnoski.com/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Sosnoski
Software Solutions, Inc.</A> 的創始人和首席顧問,他是 J2EE、XML 和 Web
服務支持方面的專家。他已經有 30 多年專業軟件開發經驗,最近幾年他集中研究服務器端的 Java 技術。Dennis
經常在全國性的會議上就 XML 和 Java 技術發表演講,他還是 <A
href="http://www.sosnoski.com/jxml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Seattle
Java-XML SIG</A> 的主席。可以通過 <A href="mailto:dms@sosnoski.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">dms@sosnoski.com</A>
與 Dennis 聯系。 </TD></TR></TBODY></TABLE></TD>
<TD width=10><IMG alt="" border=0 height=1
src="Java編程 的動態性,第 2部分:引入反射.files/c.gif" width=10></TD></TR></TBODY></TABLE><!-- END PAPER BODY--><BR clear=all><IMG
alt="" border=0 height=10 src="Java編程 的動態性,第 2部分:引入反射.files/c.gif"
width=100><BR>
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD align=right width="100%"><A
href="http://www-900.ibm.com/developerWorks/cn/java/j-dyn0603/#top">到頁首</A></TD>
<TD width=5><IMG alt="" border=0 height=1
src="Java編程 的動態性,第 2部分:引入反射.files/c.gif" width=5></TD></TR>
<TR vAlign=top>
<TD bgColor=#000000 colSpan=2><IMG alt="" border=0 height=1
src="Java編程 的動態性,第 2部分:引入反射.files/c.gif" width=100></TD></TR>
<TR vAlign=top>
<TD bgColor=#ffffff colSpan=2><IMG alt="" border=0 height=8
src="Java編程 的動態性,第 2部分:引入反射.files/c.gif" width=100></TD></TR></TBODY></TABLE>
<TABLE border=0 cellPadding=10 cellSpacing=0 width="100%">
<TBODY>
<TR vAlign=top>
<TD>
<FORM action=/developerWorks/cn/cnratings.nsf/RateArticle?CreateDocument
method=post name=getURL><INPUT name=ArticleTitle type=hidden
value="Java編程 的動態性,第 2部分:引入反射"> <INPUT name=url type=hidden>
<SCRIPT language=javascript>getURL();</SCRIPT>
<INPUT name=Zone type=hidden value=Java> <INPUT name=RedirectURL
type=hidden value=/developerWorks/cn/thankyou/feedback-java.html> <A
name=rating><B>您對這篇文章的看法如何?</B></A>
<TABLE border=0 cellPadding=0 cellSpacing=0 width=600>
<TBODY>
<TR>
<TD colSpan=5><IMG alt="" border=0 height=8
src="Java編程 的動態性,第 2部分:引入反射.files/c.gif" width=100></TD></TR>
<TR vAlign=top>
<TD width="16%"><INPUT name=Rating type=radio value=5>真棒!(5)</TD>
<TD width="20%"><INPUT name=Rating type=radio value=4>好材料 (4)</TD>
<TD width="24%"><INPUT name=Rating type=radio value=3>一般;尚可 (3)</TD>
<TD width="22%"><INPUT name=Rating type=radio value=2>需提高 (2)</TD>
<TD width="18%"><INPUT name=Rating type=radio value=1>太差!
(1)</TD></TR></TBODY></TABLE><BR><B>建議?</B><BR><TEXTAREA cols=60 name=Comments rows=5 wrap=virtual></TEXTAREA><BR><BR><INPUT type=submit value=提交反饋意見></FORM></TD></TR>
<TR vAlign=top>
<TD bgColor=#ffffff><IMG alt="" border=0 height=8
src="Java編程 的動態性,第 2部分:引入反射.files/c.gif" width=100></TD></TR></TBODY></TABLE>
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD align=right>(c) Copyright IBM Corp. 2001, (c) Copyright IBM China
2001, All Right Reserved</TD></TR>
<TR vAlign=top>
<TD class=bbg height=21> <A class=mainlink
href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=www-900.ibm.com/cn/ibm/index.shtml&origin=dwhead">關于
IBM</A><SPAN class=divider> | </SPAN><A
class=mainlink
href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=www-900.ibm.com/cn/ibm/privacy/index.shtml&origin=dwhead">隱私條約</A><SPAN
class=divider> | </SPAN><A class=mainlink
href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=www-900.ibm.com/cn/ibm/legal/index.shtml&origin=dwhead">使用條款</A><SPAN
class=divider> | </SPAN><A class=mainlink
href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=www-900.ibm.com/cn/ibm/contact/index.shtml&origin=dwhead">聯系
IBM</A></TD></TR></TBODY></TABLE>
<SCRIPT language=JavaScript1.2 src="Java編程 的動態性,第 2部分:引入反射.files/stats.js"
type=text/javascript></SCRIPT>
<NOSCRIPT><IMG alt="" border=0 height=1
src="D:\prePrj\ref\Java編程 的動態性,第 2部分:引入反射.files\c(1).gif" width=1></NOSCRIPT>
</A></BODY></HTML>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -