JAVA架構師學習方向
posted @ 2018-10-26 14:12 JavaSuns 閱讀(176) | 評論 (0) | 編輯 收藏
SunsplHello,everyone,i am sun.
天道酬勤,笨鳥先飛.
隨筆 - 47, 文章 - 0, 評論 - 24, 引用 - 0
|
POI操作package cc.dynasoft.struts.action; posted @ 2009-06-13 19:52 JavaSuns 閱讀(602) | 評論 (0) | 編輯 收藏 linux創建文件夾命令
mkdir /home/u1 創建文件夾/home/u1
chown oracle /home/u1 表示改變目錄所有者為oracle賬戶; chgrp dba /home/u1 改變/home/u1目錄為dba所有; chmod 755 /home/u1 表示oracle賬戶對/home/u1目錄有755權限; rmdir /home/u1 表示刪除/home/u1目錄 hostname可以查看linux的計算機名; whoami可以查看當前用戶; pwd顯示當前路徑; df查看系統的硬件信息 ls -lrt l表示顯示詳細列表,-t表示按時間排序,-r反向排序 cat orcl_ora_3436.trc|grep bucket 以下查看相關文件內容: more /etc/oratab cat /etc/passwd cat /etc/group posted @ 2008-07-28 09:01 JavaSuns 閱讀(38641) | 評論 (4) | 編輯 收藏 Linux中復制文件或目錄的命令(為了響應新工作,要學習一下LINUX)copy命令 該命令的功能是將給出的文件或目錄拷貝到另一文件或目錄中,同MSDOS下的copy命令一樣,功能十分強大。 語法: cp [選項] 源文件或目錄 目標文件或目錄 說明:該命令把指定的源文件復制到目標文件或把多個源文件復制到目標目錄中。 該命令的各選項含義如下: - a 該選項通常在拷貝目錄時使用。它保留鏈接、文件屬性,并遞歸地拷貝目錄,其作用等于dpR選項的組合。 - d 拷貝時保留鏈接。 - f 刪除已經存在的目標文件而不提示。 - i 和f選項相反,在覆蓋目標文件之前將給出提示要求用戶確認。回答y時目標文件將被覆蓋,是交互式拷貝。 - p 此時cp除復制源文件的內容外,還將把其修改時間和訪問權限也復制到新文件中。 - r 若給出的源文件是一目錄文件,此時cp將遞歸復制該目錄下所有的子目錄和文件。此時目標文件必須為一個目錄名。 - l 不作拷貝,只是鏈接文件。 需要說明的是,為防止用戶在不經意的情況下用cp命令破壞另一個文件,如用戶指定的目標文件名已存在,用cp命令拷貝文件后,這個文件就會被新源文件覆蓋,因此,建議用戶在使用cp命令拷貝文件時,最好使用i選項。 posted @ 2008-07-28 08:59 JavaSuns 閱讀(2316) | 評論 (0) | 編輯 收藏 解析oracle的rownum(學習)
對于rownum來說它是oracle系統順序分配為從查詢返回的行的編號,返回的第一行分配的是1,第二行是2,依此類推,這個偽字段可以用于限制查詢返回的總行數,而且rownum不能以任何表的名稱作為前綴。
舉例說明: 例如表:student(學生)表,表結構為: ID char(6) --學號 name VARCHAR2(10) --姓名 create table student (ID char(6), name VARCHAR2(100)); insert into sale values('200001',‘張一’); insert into sale values('200002',‘王二’); insert into sale values('200003',‘李三’); insert into sale values('200004',‘趙四’); commit; (1) rownum 對于等于某值的查詢條件 如 果希望找到學生表中第一條學生的信息,可以使用rownum=1作為條件。但是想找到學生表中第二條學生的信息,使用rownum=2結果查不到數據。因 為rownum都是從1開始,但是1以上的自然數在rownum做等于判斷是時認為都是false條件,所以無法查到rownum = n(n>1的自然數)。 SQL> select rownum,id,name from student where rownum=1;(可以用在限制返回記錄條數的地方,保證不出錯,如:隱式游標) SQL> select rownum,id,name from student where rownum=1; ROWNUM ID NAME ---------- ------ --------------------------------------------------- 1 200001 張一 SQL> select rownum,id,name from student where rownum =2; ROWNUM ID NAME ---------- ------ --------------------------------------------------- (2)rownum對于大于某值的查詢條件 如果想找到從第二行記錄以后的記錄,當使用rownum>2是查不出記錄的,原因是由于rownum是一個總是從1開始的偽列,Oracle 認為rownum> n(n>1的自然數)這種條件依舊不成立,所以查不到記錄 SQL> select rownum,id,name from student where rownum >2; ROWNUM ID NAME ---------- ------ --------------------------------------------------- 那如何才能找到第二行以后的記錄呀。可以使用以下的子查詢方法來解決。注意子查詢中的rownum必須要有別名,否則還是不會查出記錄來,這是因為rownum不是某個表的列,如果不起別名的話,無法知道rownum是子查詢的列還是主查詢的列。 SQL>select * from(select rownum no ,id,name from student) where no>2; NO ID NAME ---------- ------ --------------------------------------------------- 3 200003 李三 4 200004 趙四 SQL> select * from(select rownum,id,name from student)where rownum>2; ROWNUM ID NAME ---------- ------ --------------------------------------------------- (3)rownum對于小于某值的查詢條件 如果想找到第三條記錄以前的記錄,當使用rownum<3是能得到兩條記錄的。顯然rownum對于rownum<n((n>1的自然數)的條件認為是成立的,所以可以找到記錄。 SQL> select rownum,id,name from student where rownum <3; ROWNUM ID NAME ---------- ------ --------------------------------------------------- 1 200001 張一 2 200002 王二 綜 上幾種情況,可能有時候需要查詢rownum在某區間的數據,那怎么辦呀從上可以看出rownum對小于某值的查詢條件是人為true的,rownum對 于大于某值的查詢條件直接認為是false的,但是可以間接的讓它轉為認為是true的。那就必須使用子查詢。例如要查詢rownum在第二行到第三行之 間的數據,包括第二行和第三行數據,那么我們只能寫以下語句,先讓它返回小于等于三的記錄行,然后在主查詢中判斷新的rownum的別名列大于等于二的記 錄行。但是這樣的操作會在大數據集中影響速度。 SQL> select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2; NO ID NAME ---------- ------ --------------------------------------------------- 2 200002 王二 3 200003 李三 (4)rownum和排序 Oracle中的rownum的是在取數據的時候產生的序號,所以想對指定排序的數據去指定的rowmun行數據就必須注意了。 SQL> select rownum ,id,name from student order by name; ROWNUM ID NAME ---------- ------ --------------------------------------------------- 3 200003 李三 2 200002 王二 1 200001 張一 4 200004 趙四 可以看出,rownum并不是按照name列來生成的序號。系統是按照記錄插入時的順序給記錄排的號,rowid也是順序分配的。為了解決這個問題,必須使用子查詢 SQL> select rownum ,id,name from (select * from student order by name); ROWNUM ID NAME ---------- ------ --------------------------------------------------- 1 200003 李三 2 200002 王二 3 200001 張一 4 200004 趙四 這樣就成了按name排序,并且用rownum標出正確序號(有小到大) posted @ 2008-06-26 10:23 JavaSuns 閱讀(426) | 評論 (0) | 編輯 收藏 Java里的list,set,map操作方法(練習)
//ArrayList
{ ArrayList arraylist=new ArrayList(); arraylist.add(0,"end");//指定索引加入值 //需注意的是,如果現有2個值,我加入索引為5的那么就會出現異常 for(int i=0;i<2;i++){ arraylist.add(i,String.valueOf(i)); } System.out.println("ArrayList:"); for(int i=0;i<arraylist.size();i++){ System.out.print(arraylist.get(i)+";"); } arraylist.add("0");//直接加入值到ArrayList的最后 arraylist.add("0"); System.out.print("\nArrayList\'s lastIndexOf(\"0\") is "+arraylist.lastIndexOf("0")); } //Arrays { String []array=new String[]{"a","b","c"}; List list=Arrays.asList(array); System.out.println("\nArrays:"); for(int i=0;i<list.size();i++){ System.out.print(list.get(i)+";"); } System.out.print("\nArrays\'s length is "+array.length);//打印數組的長度 } //Collections { String []array=new String[]{"a","b","c"}; List list=Arrays.asList(array); Collections.fill(list,"Fill");//用Fill填充全部元素 System.out.println("\nCollections:"); for(int i=0;i<list.size();i++){ System.out.print(list.get(i)+";"); } array=new String[]{"1","2","3"}; List list2=Arrays.asList(array); Collections.copy(list,list2);//拷貝list2的數據進list System.out.println("\n"+list); Collections.swap(list,2,1);//調換索引為1和2的元素的位置 System.out.println(list); } //EventObject { String s="hello"; String s2=s; EventObject eventobject=new EventObject(s);//一個準容器類型,確切的歸類它不是容器 System.out.println("EventObject:"); System.out.println(eventobject.getSource()); System.out.println(eventobject.equals(s2)); } //HashMap { HashMap hashmap=new HashMap();//一個速度最快的容器 hashmap.put("0","c"); hashmap.put("1","a"); hashmap.put("2","b"); hashmap.put("3","a"); System.out.println("HashMap:"); System.out.println(hashmap);//該容器有其內部的排序方式 Set set=hashmap.keySet();//獲取全部鍵 Iterator iterator=set.iterator(); while(iterator.hasNext()){ System.out.print(hashmap.get(iterator.next())+";"); } } //HashSet { HashSet hashset=new HashSet();//一個絕對不能重復的類型 hashset.add("c"); hashset.add("b"); hashset.add("a"); hashset.add("a"); hashset.add("b"); System.out.println("\nHashSet:"); System.out.println(hashset); Iterator iterator=hashset.iterator();//取出元素 while(iterator.hasNext()){ System.out.print(iterator.next()+";"); } } //Hashtable { Hashtable hashtable=new Hashtable();//一個完全可以由其他容器替換的老容器類型 hashtable.put("0","c"); hashtable.put("1","a"); hashtable.put("3","c"); hashtable.put("2","b"); System.out.println("\nHashtable:"); Enumeration enumeration=hashtable.elements();//獲取元素,Enumeration已經不是主流,Iterator是它的下一代替代品 while(enumeration.hasMoreElements()){ System.out.print(enumeration.nextElement()+";"); } } //IdentityHashMap { IdentityHashMap identityhashmap=new IdentityHashMap(); identityhashmap.put("0","c"); identityhashmap.put("1","a"); identityhashmap.put("3","b"); identityhashmap.put("2","a"); System.out.println("\nIdentityHashMap:"); System.out.println(identityhashmap); System.out.println(identityhashmap.containsKey("3"));//是否包含這個鍵 System.out.println(identityhashmap.containsValue("a"));//是否包含值 Set set=identityhashmap.entrySet();//傳為Set類型 System.out.println(set); set=identityhashmap.keySet();//全部鍵 System.out.println(set); } //LinkedHashMap { LinkedHashMap linkedhashmap=new LinkedHashMap(); linkedhashmap.put("0","b"); linkedhashmap.put("2","a"); linkedhashmap.put("1","c"); linkedhashmap.put("3","b"); System.out.println("LinkedHashMap:"); System.out.println(linkedhashmap); System.out.println(linkedhashmap.containsKey("2"));//是否包含這個鍵 System.out.println(linkedhashmap.containsValue("c"));//是否包含值 Set set=linkedhashmap.keySet(); Iterator iterator=set.iterator(); while(iterator.hasNext()){ System.out.print(linkedhashmap.get(iterator.next())+";"); } } //LinkedHashSet { LinkedHashSet linkedhashset=new LinkedHashSet();//它包含了幾種Set的屬性但卻沒有自己的特色 linkedhashset.add("c"); linkedhashset.add("a"); linkedhashset.add("a"); linkedhashset.add("b"); System.out.println("\nLinkedHashSet:"); System.out.println(linkedhashset); System.out.println(linkedhashset.contains("a"));//是否包含對象 Iterator iterator=linkedhashset.iterator(); while(iterator.hasNext()){ System.out.print(iterator.next()+";"); } } //LinkedList { LinkedList linkedlist=new LinkedList();//自由使用是它的特色 linkedlist.add("a"); linkedlist.add(1,"c"); linkedlist.addLast("b"); linkedlist.addFirst("d"); System.out.println("\nLinkedList:"); System.out.println(linkedlist); //linkedlist.clear();//該方法清空容器 //linkedlist.remove(0);//刪除索引為0的元素 //linkedlist.remove("d");//刪除值為d的元素 //linkedlist.removeFirst();//刪除第一個元素 //linkedlist.removeLast();//刪除最后一個元素 for(int i=0;i<linkedlist.size();i++){ System.out.print(linkedlist.get(i)+";"); } } //Stack { Stack stack=new Stack();//堆棧 stack.add("b"); stack.add(0,"c"); stack.push("d"); stack.add("e"); stack.push("a"); Enumeration enumeration=stack.elements(); System.out.println("\nStack:"); while(enumeration.hasMoreElements()){ System.out.print(enumeration.nextElement()+";"); } //后進先出 System.out.println("\n"+stack.peek()); System.out.println(stack.pop()); System.out.println(stack.contains("d")+";"+stack.contains("a"));//是否包含該元素,有趣的事情發生了 System.out.println(stack.search("c"));//非常有用的屬性,檢索,但是由后向前的排列 } //TreeMap { TreeMap treemap=new TreeMap(); treemap.put("0","d"); treemap.put("2","a"); treemap.put("1","b"); treemap.put("3","c"); System.out.println("\nTreeMap:");//可以對鍵排序 System.out.println(treemap); System.out.println(treemap.firstKey());//返回第一個鍵 Set set=treemap.keySet(); Iterator iterator=set.iterator(); while(iterator.hasNext()){ System.out.print(treemap.get(iterator.next())+";"); } } //TreeSet { TreeSet treeset=new TreeSet();//自動排序內容 treeset.add("b"); treeset.add("a"); treeset.add("c"); treeset.add("d"); System.out.println("\nTreeSet:"); System.out.println(treeset); System.out.println(treeset.first());//返回第一個元素 Iterator iterator=treeset.iterator(); while(iterator.hasNext()){ System.out.print(iterator.next()+";"); } } //Vector { Vector vector=new Vector(); vector.add(0,"b"); vector.add("a"); vector.addElement("d"); vector.add("c"); System.out.println("\nVector:"); System.out.println(vector); vector.set(2,"h");//替換掉指定索引的元素 System.out.println(vector); Object []str=vector.toArray(); for(int i=0;i<str.length;i++){ System.out.print(str[i]+";"); } vector.setSize(2);//重新設置大小為2 System.out.println("\n"+vector); } //WeakHashMap { WeakHashMap weakhashmap=new WeakHashMap(); weakhashmap.put("1","b"); weakhashmap.put("2","c"); weakhashmap.put("0","d"); weakhashmap.put("3","a"); System.out.println("\nWeakHashMap:"); System.out.println(weakhashmap); System.out.println(weakhashmap.containsKey("3"));//是否包含鍵 System.out.println(weakhashmap.containsValue("d"));//是否包含值 Set set=weakhashmap.entrySet(); Iterator iterator=set.iterator(); while(iterator.hasNext()){ System.out.print(iterator.next()+";"); } //weakhashmap.remove("2");//刪除該鍵對應的值 //weakhashmap.get("1");//獲取指定鍵的值 } } posted @ 2008-06-25 17:33 JavaSuns 閱讀(3875) | 評論 (0) | 編輯 收藏 map,set,list,等JAVA中集合解析(了解)
在JAVA的util包中有兩個所有集合的父接口Collection和Map,它們的父子關系:
java.util +Queue 接口 +Set 接口 +Map 接口 以下對眾多接口和類的簡單說明:首先不能不先說一下數組(Array) Java所有“存儲及隨機訪問一連串對象”的做法,array是最有效率的一種。 1、 2、Java中有一個Arrays類,專門用來操作array。
若撰寫程序時不知道究竟需要多少對象,需要在空間不足時自動擴增容量,則需要使用容器類庫,array不適用。 1、Collection 和 Map 的區別 容器內每個為之所存儲的元素個數不同。 2、Java2容器類類庫的用途是“保存對象”,它分為兩類,各自旗下的子類關系 Collection Map----一組成對的“鍵值對”對象,即其元素是成對的對象,最典型的應用就是數據字典,并且還有其它廣泛的應用。另外,Map可以返回其所有鍵組成的Set和其所有值組成的Collection,或其鍵值對組成的Set,并且還可以像數組一樣擴展多維Map,只要讓Map中鍵值對的每個“值”是一個Map即可。 3、其他特征 * List,Set,Map將持有對象一律視為Object型別。
Collections是針對集合類的一個幫助類。提供了一系列靜態方法實現對各種集合的搜索、排序、線程完全化等操作。 四、如何選擇? 1、容器類和Array的區別、擇取 2、 結論:最常用的是ArrayList,HashSet,HashMap,Array。而且,我們也會發現一個規律,用TreeXXX都是排序的。
1、Collection沒有get()方法來取得某個元素。只能通過iterator()遍歷元素。 5、Map用 put(k,v) / get(k),還可以使用containsKey()/containsValue()來檢查其中是否含有某個key/value。 6、Map中元素,可以將key序列、value序列單獨抽取出來。 為什么一個生成Set,一個生成Collection?那是因為,key總是獨一無二的,value允許重復。 posted @ 2008-06-25 17:32 JavaSuns 閱讀(11779) | 評論 (1) | 編輯 收藏 項目成功的12個關鍵原則(學習)1、項目經理必須關注項目成功的三個標準 簡單地說,一是準時;二是預算控制在既定的范圍內;三是質量得到經理和用戶們的贊許。項目經理必須保證項目小組的每一位成員都能對照上面三個標準來進行工作。 2、任何事都應當先規劃再執行 就項目管理而言,很多專家和實踐人員都同意這樣一個觀點:需要項目經理投入的最重要的一件事就是規劃。只有詳細而系統的由項目小組成員參與的規劃才是項目成功的唯一基礎。當現實的世界出現了一種不適于計劃生存的環境時,項目經理應制定一個新的計劃來反映環境的變化。規劃、規劃、再規劃就是項目經理的一種生活方式。 3、項目經理必須以自己的實際行動向項目小組成員傳遞一種緊迫感 由于項目在時間、資源和經費上都是有限的,項目最終必須完成。但項目小組成員大多有自己的愛好,項目經理應讓項目小組成員始終關注項目的目標和截止期限。例如,可以定期檢查,可以召開例會,可以制作一些提醒的標志置于項目的場所。 4、成功的項目應使用一種可以度量且被證實的項目生命周期 標準的信息系統開發模型可以保證專業標準和成功的經驗能夠融入項目計劃。這類模型不僅可以保證質量,還可以使重復勞動降到最低程度。因此,當遇到時間和預算壓力需要削減項目時,項目經理應確定一種最佳的項目生命周期。 5、所有項目目標和項目活動必須生動形象地得以交流和溝通 項目經理和項目小組在項目開始時就應當形象化地描述項目的最終目標,以確保與項目有關的每一個人都能記住。項目成本的各個細節都應當清楚、明確、毫不含糊,并確保每個人對此都達成了一致的意見。 6、采用漸進的方式逐步實現目標 如果試圖同時完成所有的項目目標,只會造成重復勞動,既浪費時間又浪費錢。俗話說,一口吃不成個胖子。項目目標只能一點一點地去實現,并且每實現一個目標就進行一次評估,確保整個項目能得以控制。 7、項目應得到明確的許可,并由投資方簽字實施 在實現項目目標的過程中獲得明確的許可是非常重要的。應將投資方的簽字批準視為項目的一個出發點。道理很簡單:任何有權拒絕或有權修改項目目標的人都應當在項目啟動時審查和批準這些項目目標。 8、要想獲得項目成功必須對項目目標進行透徹的分析 研究表明,如果按照眾所周知記錄在案的業務需求來設計項目的目標,則該項目多半會成功。所以,項目經理應當堅持這樣一個原則,即在組織機構啟動項目之前,就應當為該項目在業務需求中找到充分的依據。 9、項目經理應當責權對等 項目經理應當對項目的結果負責,這一點并不過分。但與此相對應,項目經理也應被授予足夠的權利以承擔相應的責任。在某些時候,權利顯得特別重要,如獲取或協調資源,要求得到有關的中小企業的配合,做相應的對項目成功有價值的決策等等。 10、項目投資方和用戶應當主動介入,不能被動地坐享其成 多數項目投資方和用戶都能正確地要求和行使批準(全部或部分)項目目標的權力。但伴隨這個權力的是相應的責任——主動地介入項目的各個階段。例如,在項目早期要幫助確定項目目標;在項目進行中,要對完成的階段性目標進行評估,以確保項目能順利進行。項目投資方應幫助項目經理去訪問有關的中小企業和目標顧客的成員,并幫助項目經理獲得必要的文件資料。 11、項目的實施應當采用市場運作機制 在多數情況下,項目經理應將自己看成是賣主,以督促自己完成投資方和用戶交付的任務。項目計劃一旦批準項目經理應當定期提醒項目小組成員該項目必須滿足的業務需求是什么,以及該怎樣工作才能滿足這些業務需求。 12、項目經理應當獲得項目小組成員的最佳人選 最佳人選是指受過相應的技能培訓,有經驗,素質高。對于項目來說,獲得最佳人選往往能彌補時間、經費或其它方面的不足。項目經理應當為這些最佳的項目成員創造良好的工作環境,如幫助他們免受外部干擾,幫助他們獲得必要的工具和條件以發揮他們的才能。 posted @ 2008-06-15 15:43 JavaSuns 閱讀(345) | 評論 (0) | 編輯 收藏 什么是“成功項目”:談談軟件的價值(看)在開始正文之前,我想先講兩個故事——關于軟件項目的故事。
有兩個軟件項目(姑且稱之為“項目 A”和“項目 B”),它們在開始時的預算都是 50 個人月,時間是 5 個月。 項目 A 在 5 個月后完工,耗費成本 50 人月 故事二 有兩個軟件項目(仍然姑且稱之為“項目 A”和“項目 B”),它們在開始時的計劃都是交付 200 項功能。 項目 A 在項目結束時一次性交付了最初計劃的 200 項功能,但客戶發現其中大約 30 項功能沒有太大用處,而另外 30 項有用的功能要等到下一個項目才能實現。 這個問題并不容易回答——實際上它沒有標準答案。站在很多軟件企業的立場上,項目 A 是一個理想的成功項目:按時間、按成本完成預先約定的任務。請注意,我用了“理想的”這個詞,稍后我還會解釋這個有趣的詞,因為實際上的軟件項目往往沒有那么理想。 而如果換一個角度,站在客戶的立場上呢?也許付錢購買軟件的客戶會有一些不同的想法。項目 B 從開始之后一個月便交付了第一個可工作的版本,從那時起客戶就開始使用這個軟件的部分功能,并且不斷地把自己使用的感受反饋給開發團隊。在真實的業務運營過程中,客戶甚至發現了一種新的盈利模式,并進行了一次大規模的業務調整,這次調整的結果也直觀地體現在軟件項目中。雖然項目B的整體交付速率低于項目 A,但它提供的所有功能都是客戶真正需要的,它們為客戶提供實實在在的價值——更不用說,客戶提前好幾個月就開始使用這個軟件。 實際上,這是一篇關于軟件價值的文章。和“成功項目”一樣,對于“軟件的價值”,不同的人也會有不同的定義。不過作為付錢購買軟件的客戶,他對于軟件價值的定義是一目了然的:他能夠從使用軟件中創造多少價值,軟件能夠為他的業務提供多少價值,這就是軟件的價值。或者說得更簡明一點: 軟件價值源自使用 一個真實的案例 在 ThoughtWorks 的一個項目中,開發者們在項目開始之后一個月內就發布了第一個版本——只有一些簡單的數據采集功能。在發布展示會上,發生了這樣的對話…… 開發者:這是我們的第一個功能。我們從文本文件、Excel 數據表和遺留數據庫采集數據,現在我們的數據庫中有這些數據……(展示數據庫結構) 想想這個客戶會怎么定義一個“成功的軟件項目”?好吧,也許這個項目超過了預期的時間,也許投入了更多的人力,但這些并不意味著“項目失敗”——只是付出更高的成本。關鍵在于,他投入的這些成本能夠帶來多大的收益,他的投資回報率是否劃算。對于這個客戶而言,如果項目能夠隨時給他提供可用的、能夠創造最大價值的軟件,能夠隨時讓——就像故事中提到的——這種有價值的想法得以實現,這就是一個成功的項目。 所以,親愛的讀者,請你忘記本文標題上出現的“敏捷”二字,我們在這里所說的不是別的,就是一種為客戶創造最大化價值的軟件開發方法。這樣的方法有很多種,但它們有一個共同的特點:盡快、盡可能頻繁地交付可以工作的軟件,讓客戶盡快開始使用軟件,從使用中創造價值、厘清思路、提出反饋。仍然以 ThoughtWorks 的項目為例,這些項目通常在啟動開發階段之后一個月內就會發布第一個版本,隨后每一周或每兩周發布一個新版本——每個版本都是一個可以工作的軟件,每個版本都比前一個版本具有更豐富的功能,并且每個版本都包含客戶認為迄今為止最有價值的那些功能。用軟件開發的“黑話”,“開發下一個版本”的過程叫做“迭代”,這些開發方法最大的共同點就是“迭代式開發”——不是一股腦地交付全部功能,而是每次增加一點、漸進地交付最有價值的功能。 軟件開發的夢想與真實 回到文章開始處的兩個故事。我曾經說過,對于很多軟件企業而言,項目 A 是一個“理想的”成功項目。那么,是什么讓情況變得不那么理想? 答案是一個所有軟件開發者耳熟能詳的詞:需求變更。在真實的項目中,客戶通常不會等到最后一天再照單全收整個項目,因為他知道自己的業務正在發生變化。這時需求變更就出現了,伴隨著來回的扯皮和討價還價。更糟的是,大量的需求變更發生在項目晚期——因為直到這時客戶才真正看到、使用到這個軟件,他的很多想法才真正浮現成型。隨著這種“最后一分鐘的需求變更”,項目超期、超出預算也就成了家常便飯。能夠像項目A這樣完工交付的,實在是鳳毛麟角的幸運兒。 為了對付需求變更這個噩夢,軟件開發者們還發明了另一個詞:變更控制。這個有趣的詞暗示著:需求變更是一種“不好”的東西,是需要“控制”的東西。然而站在客戶的角度上想想,他在親身使用了軟件之后提出的要求,難道不是最有價值的東西嗎?把這種真正創造業務價值的要求“控制”起來,難道是合理的嗎? 在前面我也暗示過,并非所有的客戶都一定青睞迭代式開發。那么,哪些軟件項目不一定需要迭代式開發呢?從整篇文章的內容不難看出,如果客戶的業務絕對不會變化,如果客戶的需求巨細靡遺非常明確,如果客戶不需要盡快開始使用軟件以便收回成本,那么迭代式開發對他的幫助就會小得多。不過,如果讀者認真思考的話,這樣的例子也許并不多——也許比你最初認為的要少得多。一個很好的例子是“神州六號”火箭使用的計算機控制系統。還有多少這樣的例子?讀者不妨試著自己想想。 如果我足夠幸運的話,也許一些讀者已經被這篇文章吊起了胃口:既然有這么好的軟件開發方法,既然它能夠為我們創造更大的價值,那還等什么呢,我們馬上就動手吧。事情不會那么簡單。為了讓迭代式開發能夠成為現實,為了確保盡快、盡可能頻繁地交付,為了確保每次交付的都是最有價值的功能,我們——包括軟件開發者、軟件企業和客戶——需要很多的改變。這里既有職責與權利的劃分,也有開發過程和團隊的重組,還有技術層面的實踐指導。這些正是敏捷方法學所涵蓋的內容。缺少了這些東西,“為客戶創造最大價值”就只能成為一句空話。在后續的文章里,我們將結合 ThoughtWorks 的實踐經驗,逐步介紹敏捷方法的方方面面。
posted @ 2008-06-15 15:35 JavaSuns 閱讀(307) | 評論 (0) | 編輯 收藏 java與C#區別(轉)最開始時微軟公司將Java當做一種能解決C和C++中存在的問題的語言,并不在意,并繼續維持和培訓著其C和C++技術和編程人員。接下來不幸的是,正當微軟盡力在Visual J++基礎上拓展Java功能,并使之與Windows操作系統緊密結合在一起的時候,Sun公司對微軟提出法律訴訟說其違反了許可證協議中的條款,最終的結果是微軟公司不得不停止其Visual J++產品的開發。(微軟公司仍然銷售Visual J++,但是從1998年10月以來就沒有新的版本發布,并且在.Net平臺上也沒有Visual J++的位置了)接下來的事情就很清楚了,微軟公司開發了C#語言。接下來的一部分將討論C#與Java的相似性。
C#與Java的區別 C#最引人的地方是它與Java的區別而不是其相似性。下面主要來介紹C#區別于Java的不同的運行特點及Java完全沒有的特點。 中間語言 當MSIL被編譯成最終的機器碼時,微軟公司在如何選擇上是非常靈活的。微軟公司很謹慎的對外宣稱說MSIL不是解釋型的,而是被編譯成機器碼。因為開發人員都有這樣一個觀念:Java程序天生就比C程序運行慢,所以這暗示著基于MSIL的程序優于解釋型的Java字節碼。當然,既然C#和其它MSIL產品編譯器還未發布,那么這一點就還未證明,但是Java無處不在的即時編譯器使得C#和Java在效能上是一樣的。象“C#是編譯型的,Java是解釋型的”這樣話只是銷售中的技巧。Java的字節碼和MSIL碼都是的類似匯編的中間語言,在運行時執行這些中間碼。 與COM的整合 對于基于Windows的C#開發人員來說,最大的收獲是對COM的無損整合,COM是微軟Win32的組件技術。實際上,任何一種.Net體系結構上的語言最終都可能去寫COM的客戶端和服務器端程序。用C#編寫的類也會作為COM組件的子類;結果類(resulting class)也能作為COM組件使用,并作為COM組件的子類。 微軟公司的目標是使越來越多的語言都能訪問組件,并使這些組件能整合到.Net體系結構中。已有幾個廠商開始著手開發支持.Net功能的編程語言,如COBOL和Haskell。開發人員能選擇不同的語言解決不同問題,更重要的是,開發人員不必為采用.Net體系結構而必須學習新語言,可以選擇一種他們熟悉的語言。 總結 本文的第一、二部分對C#做了一膚淺的總體介紹,主要是其產生動機及與Java的相似性。第三部分則涵概了C#的語言特點。用范例說明了C#與Java兩者在相似性外,它們又是非常不同的,有許多細微的語義和設計區別,適合不同的技術和市場環境,又談到了微軟公司對C#進行標準化方面的嘗試,及其對Java的影響。 c#與java的區別
1.屬性: java中定義和訪問均要用get和set方法,可以不成對出現。 c#中是真正的屬性,定義時get和set必須同時出現,房問時用.號即可。不用get,set 2.對象索引 就是對象數組 public Story this [int index] { 3.C#中,不用任何范圍修飾符時,默認的是protect,因而不能在類外被訪問. 4.因為JAVA規定,在一個文件中只能有一個public類,而且這個類的名稱必須與文件名一模一樣,這是一個區別 5.在C#中,它是以Main方法來定位入口的.如果一個程序中沒有一個名為Main的方法,就會出"找不到入口的錯誤".不要把Main寫成main喲 6.C#預定義的簡單數據類型比Java多。例如,C#有unit,即無符號整數 7.忘掉Java中的static final修飾符。在C#中,常量可以用const關鍵詞聲明 C#的設計者還增加了readonly關鍵詞,readonly域只能通過初始化器或類的構造函數設置 8.公用類的入口點:c#是可以對Main進行重載(java中是main),允許有int返回值和空參數的Main 9.在Java中,switch語句只能處理整數。但C#中的switch語句不同,它還能夠處理字符變量。請考慮下面用switch語句處理字符串變量的C#代碼 10.C#沒有>>>移位操作符 11.goto關鍵詞: Java不用goto關鍵詞。在C#中,goto允許你轉到指定的標簽。不過,C#以特別謹慎的態度對待goto,比如它不允許goto轉入到語句塊的內部。在Java中,你可以用帶標簽的語句加上break或continue取代C#中的goto。 12.int[] x = { 0, 1, 2, 3 }; int x[] = { 0, 1, 2, 3 }; 但在C#中,只有第一行代碼合法,[]不能放到變量名字之后。 13.與Java不同的是,C#允許為名稱空間或者名稱空間中的類指定別名: using TheConsole = System.Console; 14.在Java中,包的名字同時也是實際存在的實體,它決定了放置.java文件的目錄結構。在C#中,物理的包和邏輯的名稱之間是完全分離的 .NET中包的實體稱為程序集(Assembly)。每一個程序集包含一個manifest結構。manifest列舉程序集所包含的文件,控制哪些類型和資源被顯露到程序集之外,并把對這些類型和資源的引用映射到包含這些類型與資源的文件。程序集是自包含的,一個程序集可以放置到單一的文件之內,也可以分割成多個文件。.NET的這種封裝機制解決了DLL文件所面臨的問題,即臭名昭著的DLL Hell問題。 15.在Java中,java.lang包是默認的包,C#中不存在默認的包 16.C#中的訪問修飾符與Java中的基本對應,但多出了一個internal。簡而言之,C#有5種類型的可訪問性,如下所示: public:成員可以從任何代碼訪問。 protected:成員只能從派生類訪問。 internal:成員只能從同一程序集的內部訪問。 protected internal:成員只能從同一程序集內的派生類訪問。 private:成員只能在當前類的內部訪問。 17.由于C#中不存在final關鍵詞,如果想要某個類不再被派生,你可以使用sealed關鍵詞 18.與Java不同,C#中的接口不能包含域(Field)。 另外還要注意,在C#中,接口內的所有方法默認都是公用方法。在Java中,方法聲明可以帶有public修飾符(即使這并非必要),但在C#中,顯式為接口的方法指定public修飾符是非法的。例如,下面的C#接口將產生一個編譯錯誤。 19.C#中的is操作符與Java中的instanceof操作符一樣,兩者都可以用來測試某個對象的實例是否屬于特定的類型。在Java中沒有與C#中的as操作符等價的操作符。as操作符與is操作符非常相似,但它更富有“進取心”:如果類型正確的話,as操作符會嘗試把被測試的對象引用轉換成目標類型;否則,它把變量引用設置成null。 20.C#仍舊保留了C++的內存手工管理方法,它適合在速度極端重要的場合使用,而在Java中這是不允許的 21.在C#中,所有的異常都從一個名為Exception的類派生 22.枚舉器即enum類型(java無),把它作為一個變量值的類型使用,從而把變量可能的取值范圍限制為枚舉器中出現的值。 23.結構(Struct)與類很相似,而結構是一種值類型,它存儲在棧中或者是嵌入式的,結構可以實現接口,可以象類一樣擁有成員,但結構不支持繼承 24.屬性聲明語法的第一部分與域聲明很相似,第二部分包括一個set過程和/或一個get過程 25.傳值方式: 在java中簡單數據類型的值傳參時,都以傳值方式; 在c#中如果加ref則會以引用的方式傳值(方法內部改變該參數,則外部變量一起跟著變); 加out與ref基本相同,但out不要求參數一定要初始化. 26.c#保留了指針。unsafe 27.代理:代理(delegate)可以看作C++或者其他語言中的函數指針 代理用來封裝可調用方法。你可以在類里面編寫方法并在該方法上創建代理,此后這個代理就可以被傳遞到第二個方法。這樣,第二個方法就可以調用第一個方法。 代理是從公共基類System.Delegate派生的引用類型。定義和使用代理包括三個步驟:聲明,創建實例,調用。代理用delegate聲明語法聲明。 posted @ 2008-06-15 14:37 JavaSuns 閱讀(911) | 評論 (0) | 編輯 收藏 equals 與 ==初學 Java 有段時間了,感覺似乎開始入了門,有了點兒感覺 大家先來看看一段奇怪的程序: 1. 來自 String 的憂慮 public class TestString { 2. 千變萬化的 String 3. 在 String 的游泳池中游泳 第二段程序中,使用了 new 操作符,他明白的告訴程序: 4. 繼續潛水 5. == 與 equals() 的爭斗 1. 回顧一下壞脾氣的 String 老弟 例程1: 程序輸出什么呢? 2. 哦,天哪,它又在攪混水了 例程2: 把程序簡單的更改一下: Oh MyGOD!!! 3. 你了解你的馬嗎? 解讀 String 的 API ,可以看到: 對待這個淘氣的、屢教不改的 String ,似乎沒有更好的辦法了 (1) charAt(int n) 返回字符串內n位置的字符,第一個字符位置為0, (2) concat(String str) 在原對象之后連接一個 str ,但是返回一個新的 String 對象 (3) EqualsIgnoreCase(String str) 忽略大小寫的 equals 方法 (4) trim() 返回一個新的對象,它將原對象的開頭和結尾的空白字符切掉 (5) toString() String 類也有 toString() 方法嗎? String 類還有很多其他方法,掌握他們會帶來很多方便 4. 我想買一匹更好的馬 StringBuffer 不是由 String 繼承來的 看看他的方法吧,這么多穩定可靠的方法,用起來比頑皮的 String 要有效率的多 在你無需改變字符串的情況下,簡單的 String 類就足夠你使喚的了, 5. 宰相肚里能撐船 capacity()呢? 可以看到,在內容更改之后,capacity也隨之改變了 s1 = null; s1 = ""; s1 = ""; s1 = "null"; s1 = "abc"; 總結: 多數情況下這兩者的區別就是究竟是對對象的引用進行比較還是對對象的值進行比較(其他特殊情況此處不予考慮)。==操作符是比較的對象的引用而不是對象的值。 但在最初的Object對象中的equals方法與==操作符完成功能是相同的。 對于String類的equals方法是對什么內容進行比較的呢?下面我們來看它的代碼和注釋:
posted @ 2008-06-11 22:36 JavaSuns 閱讀(738) | 評論 (0) | 編輯 收藏 |
|