哈哈,這么實現也是沒辦法的事。樓主可以想象,如果是你實現append方法,你會怎么做呢。append(null) 會將null做如何處理呢?
我想大多數人可能都會給出三種處理方案:
1. 直接返回null。一般來講,append方法都是返回一個StringBuilder對象,所以返回null,有些不符合append的設計思想。
2. 什么都不做,返回原來的StringBuilder對象。這么做似乎合理,但是往StringBuilder里放null,總得和往里放空串有點區別吧。所謂人過留名,雁過留聲。所以這種看似合理的方法卻不太好。
3. 這種方案就是現在append方法的實現方案了,將null變成"null"。
因此,將null變成"null"是最佳的方案。
re: 關于螞蟻問題(Ants) 銀河使者 2008-05-10 14:14
樓主這個想法非常的好,打滿分。
下面用數學歸納法證明一下這個算法。讓我們先來看最簡單的形式(m=1),有兩只螞蟻的情況,假設細木桿的長度為n,兩只螞蟻的位置分別為p1和p2。并且p2 > p1。其他的條件如原題。下面分別用p1和p2來代表兩只螞蟻。
對于兩只螞蟻,方向組合只有四種,分別如下:
1. p1、p2都向左 最長時間:time(p2)
2. p1、p2都向右 最長時間:time(p1)
3. p1向左、p2向右 最長時間:max(time(p1), time(n - p2))
4. p1向右、p2向左(這種情況會發生碰撞)
最長時間:max(time(n - p1), time(p2))
對于這種情況,實際上p2的時間為time(((p2 - p1) / 2 ) * 2 + n - p2 )= time(n - p1)
p1的時間為time(((p2 - p1) / 2 ) * 2 + p1) = time(p2),
從最終結果看,A- >, < -B 就相當于< -B , A - > 相當于A、B互相穿越而過,并且B只走到A最初的位置,而A也只走到B最初的位置。
從上面四種情況的最長時間可看出,正好將兩種螞蟻p1和p2可能存在的的四種可能:p1、p2、n - p1、n-p2 。我們要做的就是求這四個值的最大值,即max(time(p1)、time(p2)、time(n - p1)、time(n-p2))。 如果用文字來描述的話,就是任意一只螞蟻到達兩端的最長時間就是最終結果。
最簡單的情況已經ok了,現在假設m只螞蟻也成立,那么這m只螞蟻也可以看成是一只螞蟻,而m+1只螞蟻當然就相當于兩只螞蟻了。所以
m = 1 成立
假設m成立
而證明了m+1也成立
所以“任意一只螞蟻到達兩端的最長時間就是最終結果”的結論成立
index保存了當前數字串的索引,index.indexOf(i + 48) < 0就是判斷當前的數字的索引是否在index中(由于給定的數字串有重復的數字,因此,只能使用索引來判斷了),如果不在,就會認為這個數字還沒有加到index中,如果存在了,說明這個數已經在數字串中了。
注:i+48 ,當i=0時,正好是數字0的ASCII,以此類推
本文是Java 1.5 Tiger: A Developer's Notebook 的學習總結,沒看過《精通Hibernate》,中文的?誰寫的?如果有些雷同,估計這本英文書是最終的源頭了。
注釋就這點東西,誰講都是這些內容。上述這本英文書應該是國外最早一批講j2se5.0的書(可是2004年6出的啊),那時國內好象還沒有這種書。
如果連接字符串不在循環中,當然不需要new StringBuilder了。我的意思是說盡量讓jvm少建立StringBuilder對象。
本文只是個引子,雖然標簽是toString方法,但我們可以引申到其他的任何方法。
變量和常量都是壓棧,這在bytecode中沒有區別,就象匯編語言,根本就沒有變量和常量之分。
如下面的代碼
String s = "dd";
String ss = "ok" + s + "xyz" + 5;
System.out.println(ss);
對應的bytecode是
String s = "dd";
// 0 0:ldc1 #32 <String "dd">
// 1 2:astore_1
String ss = (new StringBuilder("ok")).append(s).append("xyz").append(5).toString();
// 2 3:new #16 <Class StringBuilder>
// 3 6:dup
// 4 7:ldc1 #34 <String "ok">
// 5 9:invokespecial #20 <Method void StringBuilder(String)>
// 6 12:aload_1
// 7 13:invokevirtual #25 <Method StringBuilder StringBuilder.append(String)>
// 8 16:ldc1 #36 <String "xyz">
// 9 18:invokevirtual #25 <Method StringBuilder StringBuilder.append(String)>
// 10 21:iconst_5
// 11 22:invokevirtual #38 <Method StringBuilder StringBuilder.append(int)>
// 12 25:invokevirtual #29 <Method String StringBuilder.toString()>
// 13 28:astore_2
System.out.println(ss);
// 14 29:getstatic #41 <Field PrintStream System.out>
// 15 32:aload_2
// 16 33:invokevirtual #47 <Method void PrintStream.println(String)>
// 17 36:return
仍然使用了StringBuilder.append(s)
另外System.out.println(new InfiniteRecursion());和 System.out.println(new InfiniteRecursion().toString());是完全一樣的,都會拋出java.lang.StackOverflowError異常
沒錯,是覆蓋或重寫(override),已經改過來了!
re: B/S,C/S架構混合使用 銀河使者 2008-05-07 19:10
我以前做過一個項目,客戶端就是用的delphi,服務端用的jsp+hibernate,效果很好。反正通訊用的都是tcp
re: B/S,C/S架構混合使用 銀河使者 2008-05-07 19:09
做C/S的客戶端不必非得用java吧,雖然Java是跨平臺的,在國內客戶端基本都是windows。個人認為客戶端用delphi、c++ builder、vb,甚至C#比較好,可以用java做服務端。java的swing、awt或是SWT做GUI遠不如delphi這些開發工具方便。如果非得要做的話,netbeans6.1提供的java gui比較好,layout也非常方便,大家可以試試。
re: B/S,C/S架構混合使用 銀河使者 2008-05-07 14:27
是的,從技術上差不多。
re: B/S,C/S架構混合使用 銀河使者 2008-05-07 09:12
實際上C/S和B/S從底層技術上沒什么區別。C/S只是模擬瀏覽器來訪問服務端資源,至于會話狀態,可以讀取http響應頭的Session-cookie信息來處理,至于安全性,客戶端可以使用https協議訪問服務端,或是自已加密數據。
re: B/S,C/S架構混合使用 銀河使者 2008-05-06 17:26
以前也做過很多這處C/S和B/S混合的項目。但有些客戶端使用的不是java。當然,服務端也非得使用象EJB一樣的重量級組件。如我做過的一個系統C/S部分的客戶端使用的是delphi,而服務端只是普通的jsp/servlet程序,也未使用web service,而是通過servlet來為C/S部分的客戶端(delphi客戶端)返回數據(也包括一些加密數據),而客戶端通過http協議訪問servlet。當然,B/S部分的還是jsp。這樣實現個人感覺比較簡單。
現在最新版的NetBeans6.1對Java GUI支持的很好,大家可以去下載試試。非常不錯。現在我感覺NetBeans在開發Java GUI、J2ME和ROR上是非常不錯的。如果開發這三類程序,NetBeans是首選
to tanleyxu
從bytecode上看是String s = "abc" 不建立String對象。其實也沒必要這么較真。至于jvm內部到底如何工作,只有看jvm的源代碼了。jvm、MSIL這些東西對String對處理都不太一樣,無法只從語意上分析。不知道tanleyxu最后這個評論:
String s1 = "Fred";
String s2 = "Fred";
// s1 == s2
String s1 = new String("Fred");
String s2 = "Fred";
// s1 != s2
String s1 = new String("Fred");
String s2 = new String("Fred");
// s1 != s2
是什么意思.如果String s = "Fred", s是壓棧操作,用的是方法棧中的空間。new String(),用的是堆的空間,這沒錯。難道我最后補充的有問題。我可不這么認為。實際上String s = "aa"確實不創建新的String。反正在bytecode里沒找到new。
下面是String s = new String("Fred")的bytecode,看看吧,只有一個new
public class Test
{
public Test()
{
// 0 0:aload_0
// 1 1:invokespecial #1 <Method void Object()>
// 2 4:return
}
public void main(String args[])
{
String s = new String("Fred");
// 0 0:new #2 <Class String>
// 1 3:dup
// 2 4:ldc1 #3 <String "Fred">
// 3 6:invokespecial #4 <Method void String(String)>
// 4 9:astore_2
// 5 10:return
}
}
還有就是在本文中我的分析有一點小毛病,就是String s = "Fred"的確在運行時不創建String對象,只是壓棧操作,另外說String s = "Fred"相當于String s = new String("Fred")也不嚴謹。從底層上它們還是有區別的。但可以肯定的是String s = new String("Fred")在當前方法中肯定是建立一個String對象,而String s = "Fred"并不創建對象。而StringBuilder的toString創建了一個String對象。這從上面的bytecode就可以看出。
四樓的Matthew Chen說的沒錯。多謝提醒。
String s = new String("Fred")這句,new 肯定是創建了一個String對象。但是"Fred",我看了一下bytecode,好象是直接壓棧了,并不創建String對象。
據說這是一道SCJP的考試題,哈哈,哪天再弄點SCJP的試題分析一下。再來幾次頭腦風暴!
activex、ole、ocx都是基于com技術的。這三種實際上都是com的具體表現。
至于dll,和其它四種沒什么關系,雖然Activex、OLE、COM、OCX的擴展名也可以是dll,但也可以是exe,或是ocx/vbx等等。
dll的種類就很多了,com組件有很多是以dll形式提供的,當然,普通的api一般也是被封在dll中。 甚至還有.net程序。
實際上,微軟在.net之前,只有兩種基本的組件技術,一個是com(在com的基礎上出現了很多其他的技術,如activex),另一個就是普通的api了,如windows kernel api。 不過有了.net ,盡盡量使用.net的技術。com注冊太麻煩,弄不好就會掉進com hell里去了。
re: 接口、類、抽象類、對象的另類解釋 銀河使者 2008-04-27 15:34
to stanleyxu
你說接口破壞了oop的規則。在我看來,先不管接口是否打破了oop。單就oop本身來說,它的存在并不是讓我們非得使用它,換句話說,我們不能為了使用oop而使用oop,就象有很多java framework,我們也不能為了使用它們而使用它們。
雖然oop從總休上說可以使大規模團隊開發成為可能,但oop從某種程度上也確實增加了程序的復雜度,只是現在程序規模的增加程度遠遠超過了oop所給我們帶來的復雜程度,因此,我們感覺oop給我們帶來了方便。
但如果各位讀過按著oop思想的編寫的源代碼。就會感覺到,讀起來,要遠比過程語言更難閱讀。當然,我承認有更好的讀oop源代碼的方法,但oop也確實正在使這個世界變得更復雜。哈哈,這個世界本來就很復雜!!多留戀當初的匯編和C語言時代啊!沒有這么多概念,一切都是tech-to-tech。不過社會在發展,當然,編程思想也得與時俱進。但愿將來出個比oop更好的編程方式或技術。最好由計算機自己去編程,那樣程序員就可以一邊喝咖啡,一邊看著自己喜歡的video。盡情地享受生活。 是不是有些象科幻啊! 我就用火箭之父齊奧爾科夫斯基話過的一句話結尾吧:昨天的夢想就是今天的希望,更是明天的現實。 但愿每個人天天做好夢,而且夢想成真!
re: 接口、類、抽象類、對象的另類解釋 銀河使者 2008-04-27 15:12
哈哈,任何東西都有缺點,抽象類也類例外。不能多繼承是目前大多數面象對象語言都存在的問題,有利必有弊。但總體上是平衡的。最好是根據具體的需要使用接口、抽象類或普通類,以及它們的任意組合。沒有絕對的好壞之分。只要能滿足要求,就是正確的選擇。
本文的目的并不是深究這些東東哪個更好,哪個不好。只是在itpub上有人不太明白接口、類、抽象類之間的關系,這是我的一個回答,希望對初學者有一些幫助。至于如何應用它們才更好,并不是本文要討論的范圍。
不過我衷心希望各位高手可以將自己的設計思想和設計理念共享出來,以便和大家分享。謝謝!
re: 接口、類、抽象類、對象的另類解釋 銀河使者 2008-04-27 13:56
總之,先有的類,然后再有的接口,接口主要是為了制定規范而存在的。如在團隊開發過程中,設計師可以會設計一系列的接口,然后所有的開發人員在開發component時,都會遵循這些接口。這樣就可以盡量避免設計和實現沖突。
就象servlet、jsp、ejb的規范都是由接口(也有抽象類)組成的。
至于抽象類,我認為是sun的設計師看到接口和類都有缺點。接口雖然可以強迫類必須實現接口的方法,但是如果多個類同時實現一個接口,而這個接口中的一些方法在這些類中的實現是完全一樣的。那么就會出現代碼冗余(雖然可以使用組合的方式解決,但仍會出現一定的代碼冗余)。因此,java就會為我們增加了抽象類,既可以強迫抽象類的子類實現某些方法,又可以達到代碼重用。
因此,也可以這么說。所有的方法都是抽象方法的抽象類就是接口,所有的方法都是普通方法的抽象類就相當于普通類(雖然不能創建抽象類的實例)
就象一個劃桿,左邊代表抽象,右邊代表具體。如果劃到最左邊,就是接口,劃到最右邊,就相當于普通類(除了不能創建實例,其他的和普通類完全一樣)。
總之,有了抽象類,就可以同時擁有接口和普通類的優點,而屏蔽了接口和普通類的缺點。
注:接口的主要缺點是不能代碼重用。
類的主要缺點是繼承一個普通類后,在創建子類實例時,父類也會創建一個實例,也就是說更耗資源,同時,也不能強迫子類必須繼承父類的某些方法。
to Matthew Chen
String s = "Fred"; 這句我查了一下bytecode,應該是一個壓棧的操作。如果要是創建String對象,就是四個String對象了。
StringBuilder類的toString確實創建了一個String對象,下面是toString方法的代碼。
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
re: 接口、類、抽象類、對象的另類解釋 銀河使者 2008-04-27 11:04
一個類當然可以有多個規格。就象一個模具,如五角星,當然可以有多個規格(如角度不同,五角星也有很多變了型的,哈哈),
接口:規格
類:模具
對象:用模具制作的產品
一個類(模具)可以實現多個接口(規格)。一個模具可以建立多個對象(產品)。
實際上,struts1或struts2的標簽根本不用記,只要知道大概有什么樣的標簽就可以了,有很多IDE(如MyEclipse)都會將這些了標簽自動列出來的,包括它們的屬性。你要知道的就是這些屬性和標簽都起什么作用就可以了,至于它們的名子,基本上不用記,頂多知道前幾個字母就可以了。
哈哈,我想沒人用記事本來編寫java程序吧(練習除外)。
那要看如何用了。一般情況下,在action類中不需要使用request和response。而只是做一跳轉的動作。這樣一來。就顯得struts1.x的execute的四個參數有些多余。因為大多數時候用不著。
我的blog:
http://www.tkk7.com/nokiaguy為什么發的是隨筆,但顯示的是文章數?
還有那么訪問總數如何出來?
忘回復