2008年1月9日
#
String中三種加法的區別
JAVA的確是一種令程序員陷入兩難境地的語言, 確切的說是思想. 它提供了如此豐富的library,讓程序員能夠很容易的寫出功能強大的程序. 同時它也封裝了如此多的細節, 讓程序員能夠輕易的寫出很拙略的程序. 它所代表的object指向思想設計之初是為了把程序員從紛繁復雜的編程細節中解放出來,來達到對已有程序的利用. 但是在編程 實際上又要求程序員了解其實現的細節而避免寫出因調用已有library不正引起的performance慢的,耗費系統資源多的程序.通常成為一個優秀的JAVA程序員需要較長時間的經驗積累,包括從程序的tuning中,或從其他有經驗的程序員口中,才知道一定功能需要怎樣實現,在程序中需要避免那些問題.但這往往是比較片面的,知其然而不知其所以然.我想大多數程序員都有類似的經歷,舉一個簡單的例子,下面有三種對String的累加操作.
① String tmp = "a" + "b" + "c";
② String tmp = null;
tmp+= "a";
tmp+= "b";
tmp+= "c";
③ String tmp = null;
StringBuffer buf = new StringBuffer();
buf.append("a");
buf.append("b");
buf.append("c");
tmp = buf.toString();
有些JAVA程序員在任意的用這三種方法的任一種,無視它們的區別.有 些程序員知道第三種方法好一直在用而不知其為什么好,以至于作為
經驗教條的傳授給JAVA新手.真正的答案是什么呢?讓我們揭開JAVA String Class和StringBuffer Class的封裝面紗看看它的內部實現.在JAVA中的String Class是一個不可變類,所有對一個Sting Object的改變都會導致一個新的String Object的生成.那么對tmp+=a中+符號的實現呢?如果你注意一下StringBuffer的Javadoc會發現.JDK對它的實現是tmp=(new StringBuffer().append(tmp).append("a")).toSting(); 這樣我們發現②這種方法在隱性生成了一個StringBuffer Object和一個String Object 再乘3就是六個object 的資源耗費.(
還不包括String Class 和StringBuffer Class內部使用的Char[])而方法③只用了兩個.也許有些程序員會對這些耗費不以為然,的確也是,不過在一些場景下它會成為perfamence的瓶頸.再回頭看看①這種方法,它會被JAVA編譯器編譯為tmp=(new StringBuffer().append("a").append("b").append("c")).to String();我們發現做的和③方法是同樣的事.
2008年1月8日
#
Class.forName(xxx.xx.xx) 返回的是一個類, .newInstance() 后才創建一個對象 Class.forName(xxx.xx.xx);的作用是要求JVM查找并加載指定的類,也就是說JVM會執行該類的靜態代碼段
Class aClass = Class.forName(xxx.xx.xx);
Object anInstance = aClass.newInstance();
這其中Class.forName("").newInstance()返回的是object
例:
Class Driver{
protected static Driver current;
public static Driver getDriver(){
return current;
}
}
Class MyDriver extends Driver{
static{
Driver.current=new MyDriver();
}
MyDriver(){}
}
用時:
Class.forName("MyDriver");
Driver d=Driver.getDriver();
有的jdbc連接數據庫的寫法里是Class.forName(xxx.xx.xx);而有一些:Class.forName(xxx.xx.xx).newInstance(),為什么會有這兩種寫法呢?
在JDBC規范中明確要求這個Driver類必須向DriverManager注冊自己,即任何一個JDBC Driver的Driver類的代碼都必須類似如下:
public class MyJDBCDriver implements Driver {
static {
DriverManager.registerDriver(new MyJDBCDriver());
}
}
所以我們在使用JDBC時只需要Class.forName(XXX.XXX);就可以了,在JDBC驅動中,有一塊靜態代碼,也叫靜態初始化塊,它執行的時間是當class調入到內存中就執行(你可以想像成,當類調用到內存后就執行一個方法)。所以很多人把jdbc driver調入到內存中,再實例化對象是沒有意義的。
2008年1月4日
#
1.RequestDispatcher.forward()
是在服務器端起作用,當使用forward()時,Servlet engine傳遞HTTP請求從當前的Servlet or JSP到另外一個Servlet,JSP 或普通HTML文件,也即你的form提交至a.jsp,在a.jsp用到了forward()重定向至b.jsp,此時form提交的所有信息在 b.jsp都可以獲得,參數自動傳遞.但forward ()無法重定向至有frame的jsp文件,可以重定向至有frame的html文件,同時forward()無法在后面帶參數傳遞,比如 servlet?name=frank,這樣不行,可以程序內通過response.setAttribute("name",name)來傳至下一個頁面.重定向后瀏覽器地址欄URL不變.
例:servlet文件中重定向
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws ServletException,IOException
{
response.setContentType("text/html; charset=gb2312");
ServletContext sc = getServletContext();
RequestDispatcher rd = null;
rd = sc.getRequestDispatcher("/index.jsp");
rd.forward(request, response);
}
2.response.sendRedirect()
是在用戶的瀏覽器端工作,sendRedirect()可以帶參數傳遞,比如servlet?name=frank傳至下個頁面,同時它可以重定向至不同的主機上,且在瀏覽器地址欄上會出現重定向頁面的URL.sendRedirect()可以重定向有frame的jsp文件.
例:servlet文件中重定向
public void doPost(HttpServletRequest request,HttpServletResponse response)
throws ServletException,IOException
{
response.setContentType("text/html; charset=gb2312");
response.sendRedirect("/index.jsp");
}
1.final修飾符
有時候,你不希望別人坐享其成,通過繼承你寫的類得到他自己所需要的類,怎么辦呢?這個時候你就可以在你的class之前加上final這個修飾府,例如public final class test{……},加上了這個修飾符之后,別人在繼承這個類的話就會編譯出錯,提示他這個類不能構建子類。從這我們可以看出,final修飾符和abstract修飾符是不能同時使用的,因為abstract類可以說是專門用來繼承的,而final類則不能用于繼承。那么如果是在方法的前面加上final修飾符有什么作用呢?比如說A類中有個聲明為final的方法a(){….},那么B繼承A的時候,B就不能覆蓋方法a(){….},否則編譯出錯,提示Cannot override the final method from A。此外,如果一個類聲明為final類的話,它里面所有的方法都自動成為final類型的。自然的,你肯定會問,如果一個域申明為final的時候有什么作用?一個屬性聲明為final之后,你不能在對它重新進行賦值,否則編譯報錯,The final field ×× cannot be assigned。另外,請注意,類聲明為final的時候,僅僅它的方法自動變為final,而屬性則不會。
2.抽象類
抽象類的用處是十分大的,特別是對于OOP而言,關于抽象類,總結幾點:
a. 抽象類不能實例化,即不能對其用new運算符;
b. 類中如果有一個或多個abstract方法,則該類必須聲明為abstract;
c. 抽象類中的方法不一定都是abstract方法,它還可以包含一個或者多個具體的方法;
d. 即使一個類中不含抽象方法,它也可以聲明為抽象類;
2008年1月3日
#
最近在編寫代碼過程中,總會寫到操作數據庫的確DAO類,這些類都是用在servlets中,操作數據頻繁,我是想問一下各位看了這個文章的大哥們,你們在寫這些類的時候,會考慮到這樣的問題不?到底是寫成static的方法好呢,還是寫成實例的方法

要是寫成靜態的方法,會不會在多線程中產生異常呢?而寫成實例的,得要每次都new 一個新的實例

看了這個文章的朋友寫下自己想法,謝謝!!
2008年1月1日
#
說明:所謂魔法數值,是指在代碼中直接出現的數值,只有在這個數值記述的那部分代碼中才能明確了解其含義。
魔法數值使代碼的可讀性大大下降。而且,如果同樣的數值多次出現時,到底這些數值是不是帶有同樣的含義呢,誰也說不清楚。另一方面,如果本來應該使用相同數值的地方,一旦用錯了,也很難發現。因此,需要注意以下幾點,極力避免使用魔法數值。
① 不使用魔法數值,代之以有名字的Static final或者enum值
在Java語言中,對有名字的值的定義,可以使用用Static final或者enum來聲明的值
注意(命名方法):在取名時一定要注意增加名字的信息量。比如,為16命名為SIXTEEN是沒有意義的。
如果16表示的是價格表的一個元素,則應該命名為PRICE_TABLE_MAX。關于命名規則,還要參照本小冊子的第6條。
② 原則上,數值就是魔法數值
但是,0,作為數組的最小下標是經常使用的。
例:for( int i = 0; I < table.leERRORth(); i++ )
讀到這里,讀者都會認為這里的0是數組的最小下標,所以在這里不認為0是魔法數值。
另外,0經常被作為變量初始化的缺省值,這時候一般也不認為0是魔法數值。
通過使用有名字的值,一方面可以提高代碼的可讀性,另一方面,也可以把變更的地方局部化,從而提高可維護性。
例子:
魔法數字的例子
int priceTable[] = new int[16]; //ERROR:這個16究竟有何含義呢?
使用了帶名字的數值的例子
static final int PRICE_TABLE_MAX = 16; //OK:帶名字
int price Table[] = new int [PRICE_TABLE_MAX]; //OK:名字的含義是很清楚的