不用new關鍵詞創建類的實例 用new關鍵詞創建類的實例時
構造函數鏈中的所有構造函數都會被自動調用
但如果一個對象實現了Cloneable接口
我們可以調用它的clone()方法
clone()方法不會調用任何類構造函數
在使用設計模式(Design Pattern)的場合
如果用Factory模式創建對象
則改用clone()方法創建新的對象實例非常簡單
例如
下面是Factory模式的一個典型實現
public static Credit getNewCredit()
{
return new Credit();
}
改進後的代碼使用clone()方法
如下所示
private static Credit
BaseCredit = new Credit();
public static Credit getNewCredit()
{
return (Credit) BaseCredit
clone();
}
上面的思路對於數組處理同樣很有用
使用非阻塞I/O 版本較低的JDK不支持非阻塞I/O API
為避免I/O阻塞
一些應用采用了創建大量線程的辦法(在較好的情況下
會使用一個緩沖池)
這種技術可以在許多必須支持並發I/O流的應用中見到
如Web服務器
報價和拍賣應用等
然而
創建Java線程需要相當可觀的開銷
JDK
引入了非阻塞的I/O庫(java
nio)
如果應用要求使用版本較早的JDK
在這裡有一個支持非阻塞I/O的軟件包
慎用異常 異常對性能不利
拋出異常首先要創建一個新的對象
Throwable接口的構造函數調用名為fillInStackTrace()的本地(Native)方法
fillInStackTrace()方法檢查堆棧
收集調用跟蹤信息
只要有異常被拋出
VM就必須調整調用堆棧
因為在處理過程中創建了一個新的對象
異常只能用於錯誤處理
不應該用來控制程序流程
不要重復初始化變量 默認情況下
調用類的構造函數時
Java會把變量初始化成確定的值
所有的對象被設置成null
整數變量(byte
short
int
long)設置成
float和double變量設置成
邏輯值設置成false
當一個類從另一個類派生時
這一點尤其應該注意
因為用new關鍵詞創建一個對象時
構造函數鏈中的所有構造函數都會被自動調用
盡量指定類的final修飾符 帶有final修飾符的類是不可派生的
在Java核心API中
有許多應用final的例子
例如java
lang
String
為String類指定final防止了人們覆蓋length()方法
另外
如果指定一個類為final
則該類所有的方法都是final
Java編譯器會尋找機會內聯(inline)所有的final方法(這和具體的編譯器實現有關)
此舉能夠使性能平均提高
%
盡量使用局部變量 調用方法時傳遞的參數以及在調用中創建的臨時變量都保存在棧(Stack)中
速度較快
其他變量
如靜態變量
實例變量等
都在堆(Heap)中創建
速度較慢
另外
依賴於具體的編譯器/JVM
局部變量還可能得到進一步優化
請參見《盡可能使用堆棧變量》
乘法和除法 考慮下面的代碼
for (val =
;
val <
; val +=
)
{
alterX = val *
;
myResult = val *
;
}
用移位操作替代乘法操作可以極大地提高性能
下面是修改後的代碼
for (val =
;
val <
;
val +=
)
{
alterX = val <<
;
myResult = val <<
;
}
修改後的代碼不再做乘以
的操作
而是改用等價的左移
位操作
每左移
位相當於乘以
相應地
右移
位操作相當於除以
值得一提的是
雖然移位操作速度快
但可能使代碼比較難於理解
所以最好加上一些注釋
二JEE篇 前面介紹的改善性能技巧適合於大多數Java應用
接下來要討論的問題適合於使用JSP
EJB或JDBC的應用
使用緩沖標記 一些應用服務器加入了面向JSP的緩沖標記功能
例如
BEA的WebLogic Server從
版本開始支持這個功能
Open Symphony工程也同樣支持這個功能
JSP緩沖標記既能夠緩沖頁面片斷
也能夠緩沖整個頁面
當JSP頁面執行時
如果目標片斷已經在緩沖之中
則生成該片斷的代碼就不用再執行
頁面級緩沖捕獲對指定URL的請求
並緩沖整個結果頁面
對於購物籃
目錄以及門戶網站的主頁來說
這個功能極其有用
對於這類應用
頁面級緩沖能夠保存頁面執行的結果
供後繼請求使用
對於代碼邏輯復雜的頁面
利用緩沖標記提高性能的效果比較明顯
反之
效果可能略遜一籌
始終通過會話Bean訪問實體Bean 直接訪問實體Bean不利於性能
當客戶程序遠程訪問實體Bean時
每一個get方法都是一個遠程調用
訪問實體Bean的會話Bean是本地的
能夠把所有數據組織成一個結構
然後返回它的值
用會話Bean封裝對實體Bean的訪問能夠改進事務管理
因為會話Bean只有在到達事務邊界時才會提交
每一個對get方法的直接調用產生一個事務
容器將在每一個實體Bean的事務之後執行一個
裝入
讀取
操作
一些時候
使用實體Bean會導致程序性能不佳
如果實體Bean的唯一用途就是提取和更新數據
改成在會話Bean之內利用JDBC訪問數據庫可以得到更好的性能
選擇合適的引用機制 在典型的JSP應用系統中
頁頭
頁腳部分往往被抽取出來
然後根據需要引入頁頭
頁腳
當前
在JSP頁面中引入外部資源的方法主要有兩種
include指令
以及include動作
include指令
例如
該指令在編譯時引入指定的資源
在編譯之前
帶有include指令的頁面和指定的資源被合並成一個文件
被引用的外部資源在編譯時就確定
比運行時才確定資源更高效
include動作
例如
該動作引入指定頁面執行後生成的結果
由於它在運行時完成
因此對輸出結果的控制更加靈活
但時
只有當被引用的內容頻繁地改變時
或者在對主頁面的請求沒有出現之前
被引用的頁面無法確定時
使用include動作才合算
在部署描述器中設置只讀屬性 實體Bean的部署描述器允許把所有get方法設置成
只讀
當某個事務單元的工作只包含執行讀取操作的方法時
設置只讀屬性有利於提高性能
因為容器不必再執行存儲操作
緩沖對EJB Home的訪問 EJB Home接口通過JNDI名稱查找獲得
這個操作需要相當可觀的開銷
JNDI查找最好放入Servlet的init()方法裡面
如果應用中多處頻繁地出現EJB訪問
最好創建一個EJBHomeCache類
EJBHomeCache類一般應該作為singleton實現
為EJB實現本地接口 本地接口是EJB
規范新增的內容
它使得Bean能夠避免遠程調用的開銷
請考慮下面的代碼
PayBeanHome home = (PayBeanHome)
javax
rmi
PortableRemoteObject
narrow
(ctx
lookup (
PayBeanHome
)
PayBeanHome
class);
PayBean bean = (PayBean)
javax
rmi
PortableRemoteObject
narrow
(home
create()
PayBean
class);
第一個語句表示我們要尋找Bean的Home接口
這個查找通過JNDI進行
它是一個RMI調用
然後
我們定位遠程對象
返回代理引用
這也是一個RMI調用
第二個語句示范了如何創建一個實例
涉及了創建IIOP請求並在網絡上傳輸請求的stub程序
它也是一個RMI調用
要實現本地接口
我們必須作如下修改
方法不能再拋出java
rmi
RemoteException異常
包括從RemoteException派生的異常
比如TransactionRequiredException
TransactionRolledBackException和NoSuchObjectException
EJB提供了等價的本地異常
如TransactionRequiredLocalException
TransactionRolledBackLocalException和NoSuchObjectLocalException
所有數據和返回值都通過引用的方式傳遞
而不是傳遞值
本地接口必須在EJB部署的機器上使用
簡而言之
客戶程序和提供服務的組件必須在同一個JVM上運行
如果Bean實現了本地接口
則其引用不可串行化
生成主鍵 在EJB之內生成主鍵有許多途徑
下面分析了幾種常見的辦法以及它們的特點
利用數據庫內建的標識機制(SQL Server的IDENTITY或Oracle的SEQUENCE)
這種方法的缺點是EJB可移植性差
由實體Bean自己計算主鍵值(比如做增量操作)
它的缺點是要求事務可串行化
而且速度也較慢
利用NTP之類的時鐘服務
這要求有面向特定平台的本地代碼
從而把Bean固定到了特定的OS之上
另外
它還導致了這樣一種可能
即在多CPU的服務器上
同一個毫秒之內生成了兩個主鍵
借鑒Microsoft的思路
在Bean中創建一個GUID
然而
如果不求助於JNI
Java不能確定網卡的MAC地址
如果使用JNI
則程序就要依賴於特定的OS
還有其他幾種辦法
但這些辦法同樣都有各自的局限
似乎只有一個答案比較理想
結合運用RMI和JNDI
先通過RMI注冊把RMI遠程對象綁定到JNDI樹
客戶程序通過JNDI進行查找
下面是一個例子
public class keyGenerator extends
UnicastRemoteObject implements Remote
{
private static long KeyValue =
System
currentTimeMillis();
public static synchronized long ge
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27355.html