摘要: 提起Java內(nèi)部類(Inner Class)可能很多人不太熟悉,實(shí)際上類似的概念在C++里也有,那就是嵌套類(Nested Class),關(guān)于這兩者的區(qū)別與聯(lián)系,在下文中會(huì)有對(duì)比。內(nèi)部類從表面上看,就是在類中又定義了一個(gè)類(下文會(huì)看到,內(nèi)部類可以在很多地方定義),而實(shí)際上并沒有那么簡(jiǎn)單,乍看上去內(nèi)部類似乎有些多余,它的用處對(duì)于初學(xué)者來說可能并不是那么顯著,但是隨著對(duì)它的深入了解,你會(huì)發(fā)現(xiàn)Java的...
閱讀全文
posted @
2010-06-30 14:26 J2EE學(xué)習(xí)筆記 閱讀(307) |
評(píng)論 (0) |
編輯 收藏
在JScript的眾多運(yùn)算符里,提供了三個(gè)邏輯運(yùn)算符&&、||和!,噢?! 是高級(jí)語言都提供的
。按我們對(duì)邏輯運(yùn)算的正常認(rèn)識(shí),邏輯運(yùn)算的結(jié)果因該是ture或者false。但是JScript的邏輯運(yùn)算卻不完全是這么定義的,這里只有!運(yùn)算符總是返回true|false,而||和&&運(yùn)算比較的好玩。
JScript對(duì)于邏輯運(yùn)算的true|false是這么定義的:
- 所有對(duì)象都被認(rèn)為是 true。
- 字符串當(dāng)且僅當(dāng)為空(""或'')時(shí)才被認(rèn)為是 false。
- null 和未定義的均被認(rèn)為是 false。
- 數(shù)字當(dāng)且僅當(dāng)為 0 時(shí)才是 false。
可是邏輯運(yùn)算符||和&&雖然遵循上面的定義規(guī)則,但是它們返回的值卻很有意思。
對(duì)于&&運(yùn)算,按照上面的規(guī)則,表達(dá)式 if ( 'abc' && '123' && new Date() ) 是執(zhí)行true分支,可是這個(gè)表達(dá)式如果寫成:
var value = 'abc' && '123' && new Date();
結(jié)果value=Fri Jan 21 00:01:17 UTC+0800 2005,原它從左到右檢測(cè),如果到了最后一個(gè)表達(dá)式也是為true的,就返回那個(gè)表達(dá)式。
對(duì)于||運(yùn)算同理,對(duì)于下面的表達(dá)式:
var value1 = 'abc' || '123' || null || false;
var value2 = null || '' || false || 'ok';
結(jié)果value1='abc',value2='ok'。這是因?yàn)閨|運(yùn)算會(huì)有"短路"特性,他也是從左向右檢測(cè),只不過它是一但發(fā)現(xiàn)有為true的值,就立即返回該表達(dá)式。
這樣的特性可以幫組我們寫出精簡(jiǎn)的代碼,可是同時(shí)也帶來代碼不便于閱讀維護(hù)的問題。
由于我手頭暫時(shí)沒有NS和moz什么的瀏覽器,不知道標(biāo)準(zhǔn)JavaScript是否也是這樣支持的?如果您方便的話,請(qǐng)告如我運(yùn)行后的結(jié)果
posted @
2010-05-13 15:11 J2EE學(xué)習(xí)筆記 閱讀(188) |
評(píng)論 (0) |
編輯 收藏
有時(shí)你可能需要對(duì)變量進(jìn)行類型檢查,或者判斷變量是否已定義。有兩種方法可以使用:typeof函數(shù)與constructor屬性。
typeof函數(shù)的用法可能不用我多說,大家都知道怎么用。而constructor屬性大家可能就陌生點(diǎn)。在《精通JavaScript》這本書中有提到construct的用法,但我用自己的幾個(gè)瀏覽器(IE7.0 / Firefox1.9 / Opera9.50)測(cè)試的結(jié)果卻和書上說的不一樣。但是仍然是有辦法通過constructor屬性來檢查變量類型的。
這里先補(bǔ)充一下,為什么明明有typeof函數(shù)可以很方便地用來檢測(cè)類型,還要用constructor呢?
因?yàn)閠ypeof會(huì)把所有的數(shù)組類型以及用戶自定義類型判斷為object,從而無法知道更確切的信息。而constructor卻可以解決這個(gè)問題。
ok,明白了我們?yōu)槭裁匆胏onstructor,現(xiàn)在讓我?guī)Т蠹乙徊讲秸J(rèn)識(shí)一下typeof和constructor用法之間的差異吧~
首先我們運(yùn)行一下下面這段代碼:
var i;
alert(typeof(i));
alert(i.constructor);
這3行代碼告訴你什么情況下可以用constructor。
你可以看到第2行返回了字符串'undefined',而第三行則發(fā)生了錯(cuò)誤,原因是i變量還沒有類型定義,自然也沒有constructor的存在。
從這一點(diǎn)上看,typeof可以檢查到變量是否有定義,而construct只能檢查已定義變量的類型。
再運(yùn)行一下下面這段代碼:
var i = 2;
alert(typeof(i));
alert(i.constructor);
alert(typeof(i.constructor));
你會(huì)看到第2行返回了字符串'number’,第3行返回了一串類似函數(shù)定義的代碼字符串(這就是跟《精通JavaScript》一書中介紹的不一樣的地方)。
我們?cè)儆胻ypeof檢查一下constructor到底是個(gè)什么樣類型的屬性,第4行返回結(jié)果'function',也就是說,實(shí)際上constructor是一個(gè)函數(shù),更確切地說是一個(gè)構(gòu)造函數(shù)。這時(shí)你就可以知道,為什么constructor可以檢查出各種類型了。
有經(jīng)驗(yàn)的程序員看到這里應(yīng)該知道要怎么利用constructor來檢查變量類型了。方法有多種,這里提供一種比較容易理解的方法。
其實(shí)想法很簡(jiǎn)單,就是把construcor轉(zhuǎn)化為字符串,通過尋找匹配字符串(function名)來確定是否指定類型。如下例子:

function user()
{};
var i = new user();
alert((i.constructor+'').match(/user/) == null);
這僅僅是個(gè)簡(jiǎn)單的例子。如果返回true則變量i不是user類型,返回false則變量是user類型。
當(dāng)然,這樣檢測(cè)是不夠精確的,比如其實(shí)他是一個(gè)myuser類型的時(shí)候,同樣會(huì)被認(rèn)為是user類。所以你需要書寫更精確的正則表達(dá)式去進(jìn)行匹配。
可以這樣簡(jiǎn)單改進(jìn)你的正則表達(dá)式:
/function user\(\)/
替換上面代碼段中的/user/。當(dāng)然,如果你的構(gòu)造函數(shù)原型是user(a),那么應(yīng)該這樣書寫你的正則表達(dá)式:
/function user\(a\)/
到這里你應(yīng)該知道怎樣使用constructor類型去檢查變量類型了吧?
ok,最后再提個(gè)醒,如果你要用基于constructor的方法去檢查一些基本類型,如
Object / Array / Function / String / Number / Boolean
在你的正則表達(dá)式中,一定要將這些單詞的首字母大寫??!而如果該類型是自定義類型,則根據(jù)你定義的時(shí)候標(biāo)識(shí)符的寫法確定。
posted @
2010-04-14 14:30 J2EE學(xué)習(xí)筆記 閱讀(321) |
評(píng)論 (0) |
編輯 收藏

/** *//**
使用三種Callback接口作為參數(shù)的query方法的返回值不同:
以ResultSetExtractor作為方法參數(shù)的query方法返回Object型結(jié)果,要使用查詢結(jié)果,我們需要對(duì)其進(jìn)行強(qiáng)制轉(zhuǎn)型;
以RowMapper接口作為方法參數(shù)的query方法直接返回List型的結(jié)果;
以RowCallbackHandler作為方法參數(shù)的query方法,返回值為void;
RowCallbackHandler和RowMapper才是我們最常用的選擇
* @author Administrator
*
*/

public class SpringTest
{

/** *//**
* 返回結(jié)果是List里裝Map,使用參數(shù),使用回調(diào) RowMapperResultSetExtractor用于處理單行記錄,
* 它內(nèi)部持有一個(gè)RowMapper實(shí)例的引用,當(dāng)處理結(jié)果集的時(shí)候, 會(huì)將單行數(shù)據(jù)的處理委派給其所持有的RowMapper實(shí)例,而其余工作它負(fù)責(zé)
*/

public void getListRowMapperResultSetExtractor()
{
ApplicationContext context = new FileSystemXmlApplicationContext(
"src/database_config.xml");
// E:\demoworkspace\spring 為工程主目錄
JdbcTemplate jt = new JdbcTemplate((DataSource) context
.getBean("oracleDataSourceTest")); // 測(cè)試用的方法

Object[] arg = new Object[]
{ 10 };
List list = (ArrayList) jt.query("select * from region where rownum<?",

arg, new RowMapperResultSetExtractor(new RowMapper()
{
public Object mapRow(ResultSet rs, int index)

throws SQLException
{
Map u = new HashMap(); //可以是自己的JavaBean值對(duì)象(簡(jiǎn)單Java對(duì)象POJO)
u.put("region_id", rs.getString("region_id"));
u.put("region_name", rs.getString("region_name"));
return u;
}
}));
Iterator it = list.iterator();

while (it.hasNext())
{
Map map = (Map) it.next();
System.out.println(map.toString());
}
}

/** *//**返回結(jié)果是List里裝Map,不使用參數(shù),使用回調(diào)
使用RowMapper比直接使用ResultSetExtractor要方便的多,只負(fù)責(zé)處理單行結(jié)果就行,現(xiàn)在,我們只需要將單行的結(jié)果組裝后返回就行,
剩下的工作,全部都是JdbcTemplate內(nèi)部的事情了。 實(shí)際上,JdbcTemplae內(nèi)部會(huì)使用一個(gè)ResultSetExtractor實(shí)現(xiàn)類來做其余的工作,
畢竟,該做的工作還得有人做不是?!
*/

public void getListRowMapper()
{
ApplicationContext context = new FileSystemXmlApplicationContext(
"src/database_config.xml");
JdbcTemplate jt = new JdbcTemplate((DataSource) context
.getBean("oracleDataSourceTest"));
List list = jt.query(

"select * from region where rownum<10", new RowMapper()
{
public Object mapRow(ResultSet rs, int index)

throws SQLException
{
Map u = new HashMap();
u.put("region_id", rs.getString("region_id"));
u.put("region_name", rs.getString("region_name"));
return u;
}
});
Iterator it = list.iterator();

while (it.hasNext())
{
Map map = (Map) it.next();
System.out.println(map.toString());
}
}
// 返回記錄集

/** *//**
RowCallbackHandler雖然與RowMapper同是處理單行數(shù)據(jù),不過,除了要處理單行結(jié)果,它還得負(fù)責(zé)最終結(jié)果的組裝和獲取工作,
在這里我們是使用當(dāng)前上下文聲明的List取得最終查詢結(jié)果, 不過,我們也可以單獨(dú)聲明一個(gè)RowCallbackHandler實(shí)現(xiàn)類,
在其中聲明相應(yīng)的集合類,這樣,我們可以通過該RowCallbackHandler實(shí)現(xiàn)類取得最終查詢結(jié)果
*/

public void getListRowCallbackHandler()
{
ApplicationContext context = new FileSystemXmlApplicationContext(
"src/database_config.xml");
JdbcTemplate jt = new JdbcTemplate((DataSource) context
.getBean("oracleDataSourceTest"));
String sql = "select * from region where region_id>?";
final List<Map> list=new ArrayList<Map>(); //一定要用final定義

Object[] params = new Object[]
{ 0 };

jt.query(sql, params, new RowCallbackHandler()
{

public void processRow(ResultSet rs) throws SQLException
{
Map u = new HashMap();
u.put("region_id", rs.getString("region_id"));
u.put("region_name", rs.getString("region_name"));
list.add(u);
}
});
Iterator it = list.iterator();

while (it.hasNext())
{
Map map = (Map) it.next();
System.out.println(map.toString());
}
}
posted @
2010-03-10 10:27 J2EE學(xué)習(xí)筆記 閱讀(569) |
評(píng)論 (0) |
編輯 收藏
摘要: 1.springJdbcContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
&nb...
閱讀全文
posted @
2010-03-09 19:10 J2EE學(xué)習(xí)筆記 閱讀(2017) |
評(píng)論 (0) |
編輯 收藏
很多朋友在深入的接觸JAVA語言后就會(huì)發(fā)現(xiàn)這樣兩個(gè)詞:反射(Reflection)和內(nèi)省(Introspector),經(jīng)常搞不清楚這到底是怎么回事,在什么場(chǎng)合下應(yīng)用以及如何使用?今天把這二者放在一起介紹,因?yàn)樗鼈兌呤窍噍o相成的。
反射
相對(duì)而言,反射比內(nèi)省更容易理解一點(diǎn)。用一句比較白的話來概括,反射就是讓你可以通過名稱來得到對(duì)象(類,屬性,方法)的技術(shù)。例如我們可以通過類名來生成一個(gè)類的實(shí)例;知道了方法名,就可以調(diào)用這個(gè)方法;知道了屬性名就可以訪問這個(gè)屬性的值。
還是寫兩個(gè)例子讓大家更直觀的了解反射的使用方法:
// 通過類名來構(gòu)造一個(gè)類的實(shí)例
Class cls_str = Class.forName( "java.lang.String" );
// 上面這句很眼熟,因?yàn)槭褂眠^ JDBC 訪問數(shù)據(jù)庫的人都用過 J
Object str = cls_str.newInstance();
// 相當(dāng)于 String str = new String();
// 通過方法名來調(diào)用一個(gè)方法
String methodName = "length" ;
Method m = cls_str.getMethod(methodName, null );
System.out.println( "length is " + m.invoke(str, null ));
// 相當(dāng)于 System.out.println(str.length());
上面的兩個(gè)例子是比較常用方法??吹缴厦娴睦泳陀腥艘l(fā)問了:為什么要這么麻煩呢?本來一條語句就完成的事情干嗎要整這么復(fù)雜?沒錯(cuò),在上面的例子中確實(shí)沒有必要這么麻煩。不過你想像這樣一個(gè)應(yīng)用程序,它支持動(dòng)態(tài)的功能擴(kuò)展,也就是說程序不重新啟動(dòng)但是可以自動(dòng)加載新的功能,這個(gè)功能使用一個(gè)具體類來表示。首先我們必須為這些功能定義一個(gè)接口類,然后我們要求所有擴(kuò)展的功能類必須實(shí)現(xiàn)我指定的接口,這個(gè)規(guī)定了應(yīng)用程序和可擴(kuò)展功能之間的接口規(guī)則,但是怎么動(dòng)態(tài)加載呢?我們必須讓應(yīng)用程序知道要擴(kuò)展的功能類的類名,比如是test.Func1,當(dāng)我們把這個(gè)類名(字符串)告訴應(yīng)用程序后,它就可以使用我們第一個(gè)例子的方法來加載并啟用新的功能。這就是類的反射,請(qǐng)問你有別的選擇嗎?
內(nèi)省
內(nèi)省是Java語言對(duì)Bean類屬性、事件的一種缺省處理方法。例如類A中有屬性name,那我們可以通過getName,setName來得到其值或者設(shè)置新的值。通過getName/setName來訪問name屬性,這就是默認(rèn)的規(guī)則。Java中提供了一套API用來訪問某個(gè)屬性的getter/setter方法,通過這些API可以使你不需要了解這個(gè)規(guī)則(但你最好還是要搞清楚),這些API存放于包java.beans中。
一般的做法是通過類Introspector來獲取某個(gè)對(duì)象的BeanInfo信息,然后通過BeanInfo來獲取屬性的描述器(PropertyDescriptor),通過這個(gè)屬性描述器就可以獲取某個(gè)屬性對(duì)應(yīng)的getter/setter方法,然后我們就可以通過反射機(jī)制來調(diào)用這些方法。下面我們來看一個(gè)例子,這個(gè)例子把某個(gè)對(duì)象的所有屬性名稱和值都打印出來:

/**//*
* Created on 2004-6-29
*/

package demo;


import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;



/** *//**
* 內(nèi)省演示例子
* @author liudong
*/


public class IntrospectorDemo
{
String name;

public static void main(String[] args) throws Exception
{
IntrospectorDemo demo = new IntrospectorDemo();
demo.setName( "Winter Lau" );

// 如果不想把父類的屬性也列出來的話,
// 那 getBeanInfo 的第二個(gè)參數(shù)填寫父類的信息
BeanInfo bi = Introspector.getBeanInfo(demo.getClass(), Object. class );
PropertyDescriptor[] props = bi.getPropertyDescriptors();

for ( int i=0;i<props.length;i++)
{
System.out.println(props[i].getName()+ "=" +
props[i].getReadMethod().invoke(demo, null ));
}

}


public String getName()
{
return name;
}


public void setName(String name)
{
this .name = name;
}
}
Web開發(fā)框架Struts中的FormBean就是通過內(nèi)省機(jī)制來將表單中的數(shù)據(jù)映射到類的屬性上,因此要求FormBean的每個(gè)屬性要有g(shù)etter/setter方法。但也并不總是這樣,什么意思呢?就是說對(duì)一個(gè)Bean類來講,我可以沒有屬性,但是只要有g(shù)etter/setter方法中的其中一個(gè),那么Java的內(nèi)省機(jī)制就會(huì)認(rèn)為存在一個(gè)屬性,比如類中有方法setMobile,那么就認(rèn)為存在一個(gè)mobile的屬性,這樣可以方便我們把Bean類通過一個(gè)接口來定義而不用去關(guān)系具體實(shí)現(xiàn),不用去關(guān)系Bean中數(shù)據(jù)的存儲(chǔ)。比如我們可以把所有的getter/setter方法放到接口里定義,但是真正數(shù)據(jù)的存取則是在具體類中去實(shí)現(xiàn),這樣可提高系統(tǒng)的擴(kuò)展性。
總結(jié)
將Java的反射以及內(nèi)省應(yīng)用到程序設(shè)計(jì)中去可以大大的提供程序的智能化和可擴(kuò)展性。有很多項(xiàng)目都是采取這兩種技術(shù)來實(shí)現(xiàn)其核心功能,例如我們前面提到的Struts,還有用于處理XML文件的Digester項(xiàng)目,其實(shí)應(yīng)該說幾乎所有的項(xiàng)目都或多或少的采用這兩種技術(shù)。在實(shí)際應(yīng)用過程中二者要相互結(jié)合方能發(fā)揮真正的智能化以及高度可擴(kuò)展性。
posted @
2010-02-04 13:42 J2EE學(xué)習(xí)筆記 閱讀(376) |
評(píng)論 (1) |
編輯 收藏
摘要: 原文出處:http://blog.chenlb.com/2008/11/join-or-countdownlatch-make-main-thread-wait-all-sub-thread.html
在編寫多線程的工作中,有個(gè)常見的問題:主線程(main) 啟動(dòng)好幾個(gè)子線程(task)來完成并發(fā)任務(wù),主線程要等待所有的子線程完成之后才繼續(xù)執(zhí)行main的其它任務(wù)。
默認(rèn)主線程退出時(shí)其它子線程不...
閱讀全文
posted @
2010-01-26 18:00 J2EE學(xué)習(xí)筆記 閱讀(1207) |
評(píng)論 (0) |
編輯 收藏
這是jQuery里常用的2個(gè)方法。
他們2者功能是完全不同的,而初學(xué)者往往會(huì)被誤導(dǎo)。
首先 我們看.find()方法:
現(xiàn)在有一個(gè)頁面,里面HTML代碼為:
<div class="css">
<p class="rain">測(cè)試1</p>
</div>
<div class="rain">
<p>測(cè)試2</p>
</div>
如果我們使用find()方法:
var $find = $("div").find(".rain");
alert( $find.html() );
將會(huì)輸出:

如果使用filter()方法:
var $filter = $("div").filter(".rain");
alert( $filter.html() );
將會(huì)輸出:

也許你已經(jīng)看出它們的區(qū)別了。
find()會(huì)在div元素內(nèi) 尋找 class為rain 的元素。
而filter()則是篩選div的class為rain的元素。
一個(gè)是對(duì)它的子集操作,一個(gè)是對(duì)自身集合元素篩選。
另外find()其實(shí)還可以用選擇器表示:
var $select = $("div .rain");
posted @
2009-11-09 16:00 J2EE學(xué)習(xí)筆記 閱讀(376) |
評(píng)論 (0) |
編輯 收藏
以前在Windows上ssh登錄一直都是用putty,雖然它簡(jiǎn)單小巧,但畢竟缺少很多特性。今天試了一下SecureCRT,感覺用起來比Putty好多了,但SecureCRT默認(rèn)的字體超難看,而且中文字體設(shè)置也比較麻煩一點(diǎn),在這里記錄一下以后可能還用得到。
- 在“會(huì)話選項(xiàng)”的“終端->仿真”里面選“Linux”,如果需要顯示顏色的話需要把“ANSI顏色”選上
- 在“外觀->字體”中選擇喜歡的字體,但這里對(duì)字體是有要求的,只有等寬字體才行。如果要正常顯示中文的話,所選擇的字體還必須包含中文字符。
- 另外就是根據(jù)你要登錄的主機(jī)的字符編碼選擇字符編碼,一般是 “UTF-8″
簡(jiǎn)單的幾步下來就設(shè)置好了,如果還有亂碼的話就退出然后重新登陸一下。如果你想所有的連接都使用這個(gè)默認(rèn)配置,可以在“全局選項(xiàng)”中設(shè)置“默認(rèn)的會(huì)話選項(xiàng)”,這樣以后新建的連接會(huì)自動(dòng)應(yīng)用上面的設(shè)置了。
PS:
以前用putty的時(shí)候,字體就直接用我在Linux最愛的Monaco,但在SecureCRT中用Monaco字體的話,中文會(huì)顯示為亂碼,這是因?yàn)镸onaco字體中不包含中文字符,而SecureCRT也不會(huì)自動(dòng)的選擇系統(tǒng)默認(rèn)的中文字體。
為了解決這個(gè)問題,我們只要去找一個(gè)包含中文的等寬字體來用,我從網(wǎng)上找了一個(gè)Consolas和雅黑的混合字體,雖然沒有Monaco好看,但效果也還不錯(cuò)。這里有個(gè)地方需要注意一下,在選擇這個(gè)字體的字體選擇對(duì)話框中,字體的默認(rèn)字符集是“西方”,需要改成CHINESE_GB2312。
如果你也想用這個(gè)字體的話,可以從這里下載。
posted @
2009-09-14 14:14 J2EE學(xué)習(xí)筆記 閱讀(6058) |
評(píng)論 (0) |
編輯 收藏
這些操作對(duì)經(jīng)常使用hibernate的同學(xué)已經(jīng)很熟悉了,我也經(jīng)常用但一些細(xì)節(jié)并不了解,
最近遇到問題才開始有看了一下。
在讀完robbin的這兩個(gè)精華貼的時(shí)候,感覺清晰了很多,確實(shí)好文章。
http://www.javaeye.com/topic/2712
http://www.javaeye.com/topic/1604?page=1
還有這個(gè)精華貼
http://www.javaeye.com/topic/7484
也很不錯(cuò)。
里面總結(jié)的很好了,我結(jié)合以上三個(gè)帖子、自己的試驗(yàn)(版本hibernate-3.0.5)和Hibernate文檔也總結(jié)了一點(diǎn),加深理解。希望對(duì)剛開始學(xué)Hibernate的同學(xué)有所幫助。
一、saveorUpdate與unsaved-value
到底是sava還是update
Hibernate需要判斷被操作的對(duì)象究竟是一個(gè)已經(jīng)持久化過的持久對(duì)象還是臨時(shí)對(duì)象。
1).主鍵Hibernate的id generator產(chǎn)生
<id name="id" type="java.lang.Long">
<column name="ID" precision="22" scale="0" />
<generator class="increment" />
</id>
Project project = new Project();
project.setId(XXX);
this.projectDao.saveOrUpdate(project);
1、默認(rèn)unsaved-value="null"
主鍵是對(duì)象類型,hebernate判斷project的主鍵是否位null,來判斷project是否已被持久化
是的話,對(duì)project對(duì)象發(fā)送save(project),
若自己設(shè)置了主鍵則直接生成update的sql,發(fā)送update(project),即便數(shù)據(jù)庫里沒有那條記錄。
主鍵是基本類型如int/long/double/
自己設(shè)置unsaved-null="0"。
所以這樣的話save和update操作肯定不會(huì)報(bào)錯(cuò)。
2、unsaved-value="none",
由于不論主鍵屬性為任何值,都不可能為none,因此Hibernate總是對(duì)project對(duì)象發(fā)送update(project)
3、unsaved-value="any"
由于不論主鍵屬性為任何值,都肯定為any,因此Hibernate總是對(duì)project對(duì)象發(fā)送save(project),hibernate生成主鍵。
Hibernate文檔中寫到
saveOrUpdate()完成了如下工作:
如果對(duì)象已經(jīng)在這個(gè)session中持久化過了,什么都不用做
如果對(duì)象沒有標(biāo)識(shí)值,調(diào)用save()來保存它
如果對(duì)象的標(biāo)識(shí)值與unsaved-value中的條件匹配,調(diào)用save()來保存它
如果對(duì)象使用了版本(version或timestamp),那么除非設(shè)置unsaved-value="undefined",版本檢查會(huì)發(fā)生在標(biāo)識(shí)符檢查之前.
如果這個(gè)session中有另外一個(gè)對(duì)象具有同樣的標(biāo)識(shí)符,拋出一個(gè)異常
2).主鍵由自己來賦值
<id name="id" type="java.lang.Long">
<column name="ID" precision="22" scale="0" />
<generator class="assigned" />
</id>
Project project = new Project();
project.setId(XXX);
this.projectDao.saveOrUpdate(project);
1、默認(rèn)unsaved-value="null"
這時(shí)有所不同,hibernate會(huì)根據(jù)主鍵產(chǎn)生一個(gè)select,來判斷此對(duì)象是否已被持久化
已被持久化則update,未被持久化則save。
2、unsaved-value="none",update對(duì)象,同上
3、unsaved-value="any" ,save對(duì)象,
如果自己自己設(shè)置的ID在數(shù)據(jù)庫中已存在,則報(bào)錯(cuò)。
二、save與update操作
顯式的使用session.save()或者session.update()操作一個(gè)對(duì)象的時(shí)候,實(shí)際上是用不到unsaved-value的
在同一Session,save沒什么可說得
update對(duì)象時(shí), 最直接的更改一個(gè)對(duì)象的方法就是load()它,保持Session打開,然后直接修改即可:
Session s =…
Project p = (Project) sess.load(Project.class, id) );
p.setName(“test”);
s.flush();
不用調(diào)用s.update(p);hibernate能察覺到它的變化,會(huì)自動(dòng)更新。當(dāng)然顯示調(diào)用的話也不會(huì)錯(cuò)
Hibernate文檔中寫到
update()方法在下列情形下使用:
程序在前面的session中裝載了對(duì)象
對(duì)象被傳遞到UI(界面)層
對(duì)該對(duì)象進(jìn)行了一些修改
對(duì)象被傳遞回業(yè)務(wù)層
應(yīng)用程序在第二個(gè)session中調(diào)用update()保存修改
三、delete操作
刪除時(shí)直接自己構(gòu)造一個(gè)project即可刪除
this.projectDao.delete(preojct);
以前刪除我是這樣寫的
public void deleteProject(String id) {
Project project = (Project) this.projectDao.get(Project.class, id);
if (project != null) {
this.projectDao.delete(project);
}
即這樣也是可以的
Project project = new Project();
project.setId(id);
this.projectDao.delete(project).
如果有級(jí)聯(lián)關(guān)系,需要把級(jí)聯(lián)的子類也構(gòu)造出來add進(jìn)去,同樣可以刪除。
好了,羅嗦的夠多了。
posted @
2009-08-27 14:44 J2EE學(xué)習(xí)筆記 閱讀(496) |
評(píng)論 (0) |
編輯 收藏
當(dāng)你顯式的使用session.save()或者session.update()操作一個(gè)對(duì)象的時(shí)候,實(shí)際上是用不到unsaved-value的。某些情況下(父子表關(guān)聯(lián)保存),當(dāng)你在程序中并沒有顯式的使用save或者update一個(gè)持久對(duì)象,那么Hibernate需要判斷被操作的對(duì)象究竟是一個(gè)已經(jīng)持久化過的持久對(duì)象,是一個(gè)尚未被持久化過的內(nèi)存臨時(shí)對(duì)象。例如:
Session session =
;
Transaction tx =
;

Parent parent = (Parent); session.load(Parent.class, id);;

Child child = new Child();;
child.setParent(parent);;
child.setName("sun");;

parent.addChild(child);;
s.update(parent);;

s.flush();;
tx.commit();;
s.close();;
在上例中,程序并沒有顯式的session.save(child); 那么Hibernate需要知道child究竟是一個(gè)臨時(shí)對(duì)象,還是已經(jīng)在數(shù)據(jù)庫中有的持久對(duì)象。如果child是一個(gè)新創(chuàng)建的臨時(shí)對(duì)象(本例中就是這種情況),那么Hibernate應(yīng)該自動(dòng)產(chǎn)生session.save(child)這樣的操作,如果child是已經(jīng)在數(shù)據(jù)庫中有的持久對(duì)象,那么Hibernate應(yīng)該自動(dòng)產(chǎn)生session.update(child)這樣的操作。
因此我們需要暗示一下Hibernate,究竟child對(duì)象應(yīng)該對(duì)它自動(dòng)save還是update。在上例中,顯然我們應(yīng)該暗示Hibernate對(duì)child自動(dòng)save,而不是自動(dòng)update。那么Hibernate如何判斷究竟對(duì)child是save還是update呢?它會(huì)取一下child的主鍵屬性 child.getId() ,這里假設(shè)id是 java.lang.Integer類型的。如果取到的Id值和hbm映射文件中指定的unsave-value相等,那么Hibernate認(rèn)為child是新的內(nèi)存臨時(shí)對(duì)象,發(fā)送save,如果不相等,那么Hibernate認(rèn)為child是已經(jīng)持久過的對(duì)象,發(fā)送update。
unsaved-value="null" (默認(rèn)情況,適用于大多數(shù)對(duì)象類型主鍵 Integer/Long/String/...)
當(dāng)Hibernate取一下child的Id,取出來的是null(在上例中肯定取出來的是null),和unsaved-value設(shè)定值相等,發(fā)送save(child)
當(dāng)Hibernate取一下child的id,取出來的不是null,那么和unsaved-value設(shè)定值不相等,發(fā)送update(child)
例如下面的情況:
Session session =
;
Transaction tx =
;

Parent parent = (Parent); session.load(Parent.class, id);;
Child child = (Child); session.load(Child.class, childId);;

child.setParent(parent);;
child.setName("sun");;

parent.addChild(child);;
s.update(parent);;

s.flush();;
tx.commit();;
s.close();;
child已經(jīng)在數(shù)據(jù)庫中有了,是一個(gè)持久化的對(duì)象,不是新創(chuàng)建的,因此我們希望Hibernate發(fā)送update(child),在該例中,Hibernate取一下child.getId(),和unsave-value指定的null比對(duì)一下,發(fā)現(xiàn)不相等,那么發(fā)送update(child)。
BTW: parent對(duì)象不需要操心,因?yàn)槌绦蝻@式的對(duì)parent有l(wèi)oad操作和update的操作,不需要Hibernate自己來判斷究竟是save還是update了。我們要注意的只是child對(duì)象的操作。另外unsaved-value是定義在Child類的主鍵屬性中的。
<class name="Child" table="child">
<id column="id" name="id" type="integer" unsaved-value="null">
<generator class="identity"/>
</id>


</class>
如果主鍵屬性不是對(duì)象型,而是基本類型,如int/long/double/...,那么你需要指定一個(gè)數(shù)值型的unsaved-value,例如:
unsaved-value="0"
在此提醒大家,很多人以為對(duì)主鍵屬性定義為int/long,比定義為Integer/Long運(yùn)行效率來得高,認(rèn)為基本類型不需要進(jìn)行對(duì)象的封裝和解構(gòu)操作,因此喜歡把主鍵定義為int/long的。但實(shí)際上,Hibernate內(nèi)部總是把主鍵轉(zhuǎn)換為對(duì)象型進(jìn)行操作的,就算你定義為int/long型的,Hibernate內(nèi)部也要進(jìn)行一次對(duì)象構(gòu)造操作,返回給你的時(shí)候,還要進(jìn)行解構(gòu)操作,效率可能反而低也說不定。因此大家一定要扭轉(zhuǎn)一個(gè)觀點(diǎn),在Hibernate中,主鍵屬性定義為基本類型,并不能夠比定義為對(duì)象型效率來的高,而且也多了很多麻煩,因此建議大家使用對(duì)象型的Integer/Long定義主鍵。
unsaved-value="none"和
unsaved-value="any"
主主要用在主鍵屬性不是通過Hibernate生成,而是程序自己setId()的時(shí)候。
在這里多說一句,強(qiáng)烈建議使用Hibernate的id generator,或者你可以自己擴(kuò)展Hibernate的id generator,特別注意不要使用有實(shí)際含義的字段當(dāng)做主鍵來用!例如用戶類User,很多人喜歡用用戶登陸名稱做為主鍵,這是一個(gè)很不好的習(xí)慣,當(dāng)用戶類和其他實(shí)體類有關(guān)聯(lián)關(guān)系的時(shí)候,萬一你需要修改用戶登陸名稱,一改就需要改好幾張表中的數(shù)據(jù)。偶合性太高,而如果你使用無業(yè)務(wù)意義的id generator,那么修改用戶名稱,就只修改user表就行了。
由這個(gè)問題引申出來,如果你嚴(yán)格按照這個(gè)原則來設(shè)計(jì)數(shù)據(jù)庫,那么你基本上是用不到手工來setId()的,你用Hibernate的id generator就OK了。因此你也不需要了解當(dāng)
unsaved-value="none"和
unsaved-value="any"
究竟有什么含義了。如果你非要用assigned不可,那么繼續(xù)解釋一下:
unsaved-value="none" 的時(shí)候,由于不論主鍵屬性為任何值,都不可能為none,因此Hibernate總是對(duì)child對(duì)象發(fā)送update(child)
unsaved-value="any" 的時(shí)候,由于不論主鍵屬性為任何值,都肯定為any,因此Hibernate總是對(duì)child對(duì)象發(fā)送save(child)
大多數(shù)情況下,你可以避免使用assigned,只有當(dāng)你使用復(fù)合主鍵的時(shí)候不得不手工setId(),這時(shí)候需要你自己考慮究竟怎么設(shè)置unsaved-value了,根據(jù)你自己的需要來定。
BTW: Gavin King強(qiáng)烈不建議使用composite-id,強(qiáng)烈建議使用UserType。
因此,如果你在系統(tǒng)設(shè)計(jì)的時(shí)候,遵循如下原則:
1、使用Hibernate的id generator來生成無業(yè)務(wù)意義的主鍵,不使用有業(yè)務(wù)含義的字段做主鍵,不使用assigned。
2、使用對(duì)象類型(String/Integer/Long/...)來做主鍵,而不使用基礎(chǔ)類型(int/long/...)做主鍵
3、不使用composite-id來處理復(fù)合主鍵的情況,而使用UserType來處理該種情況。
那么你永遠(yuǎn)用的是unsaved-value="null" ,不可能用到any/none/..了。
posted @
2009-08-17 22:41 J2EE學(xué)習(xí)筆記 閱讀(943) |
評(píng)論 (0) |
編輯 收藏
問題的提出:
如果我們編譯運(yùn)行下面這個(gè)程序會(huì)看到什么?

public class Test
{

public static void main(String args[])
{
System.out.println(0.05 + 0.01);
System.out.println(1.0 - 0.42);
System.out.println(4.015 * 100);
System.out.println(123.3 / 100);
}
}
你沒有看錯(cuò)!結(jié)果確實(shí)是
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999
Java中的簡(jiǎn)單浮點(diǎn)數(shù)類型float和double不能夠進(jìn)行運(yùn)算。不光是Java,在其它很多編程語言中也有這樣的問題。在大多數(shù)情況下,計(jì)算的結(jié)果是準(zhǔn)確的,但是多試幾次(可以做一個(gè)循環(huán))就可以試出類似上面的錯(cuò)誤?,F(xiàn)在終于理解為什么要有BCD碼了。
這個(gè)問題相當(dāng)嚴(yán)重,如果你有9.999999999999元,你的計(jì)算機(jī)是不會(huì)認(rèn)為你可以購買10元的商品的。
在有的編程語言中提供了專門的貨幣類型來處理這種情況,但是Java沒有?,F(xiàn)在讓我們看看如何解決這個(gè)問題。
四舍五入
我們的第一個(gè)反應(yīng)是做四舍五入。Math類中的round方法不能設(shè)置保留幾位小數(shù),我們只能象這樣(保留兩位):

public double round(double value)
{
return Math.round(value * 100) / 100.0;
}
非常不幸,上面的代碼并不能正常工作,給這個(gè)方法傳入4.015它將返回4.01而不是4.02,如我們?cè)谏厦婵吹降?br style="font-family: " />
4.015*100=401.49999999999994
因此如果我們要做到精確的四舍五入,不能利用簡(jiǎn)單類型做任何運(yùn)算
java.text.DecimalFormat也不能解決這個(gè)問題:
System.out.println(new java.text.DecimalFormat("0.00").format(4.025));
輸出是4.02
BigDecimal
在《Effective Java》這本書中也提到這個(gè)原則,float和double只能用來做科學(xué)計(jì)算或者是工程計(jì)算,在商業(yè)計(jì)算中我們要用java.math.BigDecimal。BigDecimal一共有4個(gè)夠造方法,我們不關(guān)心用BigInteger來夠造的那兩個(gè),那么還有兩個(gè),它們是:
BigDecimal(double val)
Translates a double into a BigDecimal.
BigDecimal(String val)
Translates the String repre sentation of a BigDecimal into a BigDecimal.
上面的API簡(jiǎn)要描述相當(dāng)?shù)拿鞔_,而且通常情況下,上面的那一個(gè)使用起來要方便一些。我們可能想都不想就用上了,會(huì)有什么問題呢?等到出了問題的時(shí)候,才發(fā)現(xiàn)上面哪個(gè)夠造方法的詳細(xì)說明中有這么一段:
Note: the results of this constructor can be somewhat unpredictable. One might assume that new BigDecimal(.1) is exactly equal to .1, but it is actually equal to .1000000000000000055511151231257827021181583404541015625. This is so because .1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the long value that is being passed in to the constructor is not exactly equal to .1, appearances nonwithstanding.
The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal(".1") is exactly equal to .1, as one would expect. Therefore, it is generally recommended that the (String) constructor be used in preference to this one.
原來我們?nèi)绻枰_計(jì)算,非要用String來夠造BigDecimal不可!在《Effective Java》一書中的例子是用String來夠造BigDecimal的,但是書上卻沒有強(qiáng)調(diào)這一點(diǎn),這也許是一個(gè)小小的失誤吧。
解決方案
現(xiàn)在我們已經(jīng)可以解決這個(gè)問題了,原則是使用BigDecimal并且一定要用String來夠造。
但是想像一下吧,如果我們要做一個(gè)加法運(yùn)算,需要先將兩個(gè)浮點(diǎn)數(shù)轉(zhuǎn)為String,然后夠造成BigDecimal,在其中一個(gè)上調(diào)用add方法,傳入另一個(gè)作為參數(shù),然后把運(yùn)算的結(jié)果(BigDecimal)再轉(zhuǎn)換為浮點(diǎn)數(shù)。你能夠忍受這么煩瑣的過程嗎?下面我們提供一個(gè)工具類Arith來簡(jiǎn)化操作。它提供以下靜態(tài)方法,包括加減乘除和四舍五入:
public static double add(double v1,double v2)
public static double sub(double v1,double v2)
public static double mul(double v1,double v2)
public static double div(double v1,double v2)
public static double div(double v1,double v2,int scale)
public static double round(double v,int scale)
附錄
源文件Arith.java:
import java.math.BigDecimal;


public class Arith
{
//默認(rèn)除法運(yùn)算精度
private static final int DEF_DIV_SCALE = 10;

//這個(gè)類不能實(shí)例化
private Arith()

{
;
}

/** *//**
* 提供精確的加法運(yùn)算。
* @param v1 被加數(shù)
* @param v2 加數(shù)
* @return 兩個(gè)參數(shù)的和
*/
public static double add(double v1,double v2)

{
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}

/** *//**
* 提供精確的減法運(yùn)算。
* @param v1 被減數(shù)
* @param v2 減數(shù)
* @return 兩個(gè)參數(shù)的差
*/

public static double sub(double v1,double v2)
{
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}

/** *//**
* 提供精確的乘法運(yùn)算。
* @param v1 被乘數(shù)
* @param v2 乘數(shù)
* @return 兩個(gè)參數(shù)的積
*/
public static double mul(double v1,double v2)

{
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}

/** *//**
* 提供(相對(duì))精確的除法運(yùn)算,當(dāng)發(fā)生除不盡的情況時(shí),精確到
* 小數(shù)點(diǎn)以后10位,以后的數(shù)字四舍五入。
* @param v1 被除數(shù)
* @param v2 除數(shù)
* @return 兩個(gè)參數(shù)的商
*/
public static double div(double v1,double v2)

{
return div(v1,v2,DEF_DIV_SCALE);
}

/** *//**
* 提供(相對(duì))精確的除法運(yùn)算。當(dāng)發(fā)生除不盡的情況時(shí),由scale參數(shù)指
* 定精度,以后的數(shù)字四舍五入。
* @param v1 被除數(shù)
* @param v2 除數(shù)
* @param scale 表示表示需要精確到小數(shù)點(diǎn)以后幾位。
* @return 兩個(gè)參數(shù)的商
*/
public static double div(double v1,double v2,int scale)

{
if(scale<0)

{
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}

/** *//**
* 提供精確的小數(shù)位四舍五入處理。
* @param v 需要四舍五入的數(shù)字
* @param scale 小數(shù)點(diǎn)后保留幾位
* @return 四舍五入后的結(jié)果
*/
public static double round(double v,int scale)

{
if(scale<0)

{
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = new BigDecimal("1");
return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
}
posted @
2009-05-07 11:33 J2EE學(xué)習(xí)筆記 閱讀(1200) |
評(píng)論 (0) |
編輯 收藏
在用AJAX(結(jié)合Struts)做一個(gè)聯(lián)動(dòng)下拉框的過程中,后臺(tái)action中返回的XML用如下javascript代碼解析

function parseMessage()
{
var xmlDoc=req.responseXML.documentElement;
var xSel=xmlDoc.getElementsByTagName("addr4");
}
奇怪的是 var xSel = xmlDoc.getElementsByTagName("addr4") 始終無法取得若干個(gè) <addr4>XXX</addr4> 內(nèi)容, 在網(wǎng)上查也都是這種寫法,搞了一個(gè)下午弄的我頭暈?zāi)X脹。最后同事一語提醒了我,在action中加入以下代碼,問題解決:
response.setContentType("text/xml;charset=UTF-8");
response.setHeader("Cache-control","no-cache");
結(jié)論:如果沒有這兩句,返回值不會(huì)被當(dāng)做XML處理,當(dāng)然就取不到 addr4 節(jié)點(diǎn)
2008.10.22 補(bǔ)充:有的人寫將上面的第一句簡(jiǎn)化成:
response.setContentType("text/xml");
這樣做如果返回的XML中沒有中文時(shí)沒問題,但是如果返回的XML中存在中文的話,也會(huì)無法取得返回的XML
posted @
2008-10-09 19:55 J2EE學(xué)習(xí)筆記 閱讀(284) |
評(píng)論 (0) |
編輯 收藏