天天看點

Java開發成長之路第一年介紹前言封裝、繼承、多态方法的重寫的重載Java接口、類(抽象)的概念Java的集合(Collection)體系Java流(Stream)體系Java異常(Exception)體系Java多線程(Thread)設計模式“單例”反射Java使用者界面程式設計SwingJava網絡程式設計JSP原理jQuery常用方法JavaScript基本概念各種浏覽器的調試技巧內建開發工具Eclipse的熟練使用應用伺服器配置資料庫Struts2架構Hibernate架構Spring架構本系列文章

本文總結了要走java開發這條路的成長軌迹。歡迎各位看客留下腳印。

正文開始之前,先申明幾點:本文說的“java開發”指的是以java後端為主、少量的前端開發,如果要了解更多前端開發的内容請移步;另外,本文假設您在學習java之前沒有其他語言的基礎。

這是一個系列的文章,而且會長期更新,歡迎各位看客關注!

這時候,作為剛剛加入“碼農”行列的您,還是有幾點是必須要搞定的:java文法、行業代碼規範(類、方法、變量等的命名規範)、計算機基本的運作原理、java程式運作的基本原理。我這裡說的“搞定”的更加準确的含義指的是:要很掌握的很熟練。因為這就像是樓梯的第一個台階、高樓大廈的地基一樣,它直接影響你後續階段的發展。

您别小瞧這幾點,以為在學校裡就早早地對java文法很了解了;不止您在成長,java本身也在發展中,是以java的不同版本之間可能也會有或大或小、或多或少的差異,忽略這一點的童鞋可能會被“絆腳石”磕碰的很慘。

程式是運作在計算機上的,為了以後的發展,可以說對計算機的原理研究的不管多麼深入都是很有必要的。但現在,你至少要對cpu、記憶體、硬碟、網卡等大部件的性能參數有所了解。

而java呢,是需要編譯為class檔案(而不是機器碼),然後在虛拟機(jvm)上運作的。這一點,決定了java是跨平台(linux、windows等)的,也決定了它可能會比c語言要運作的慢一點。它的記憶體管理機制,又決定了java是比較耗記憶體的——雖然所占用的記憶體并不是時時刻刻都需要的。

以上三點相對來說都是比較範範的東西,下面我來說一下對于初出茅廬的java程式員們有哪些技能是必須掌握的,換句話說說,掌握了下面的内容你就可以輕松應對一些面試了:

學java或者其他面向對象的童鞋們,這三個特性應該都是記得很清楚。它很重要,會一直貫穿你的java開發生涯;但這六個字過于濃縮、抽象,是很難了解的。其實,我建議作為java開發人員的第一年,反而可以忘記這些特性,先是多多動手,積累一些項目經驗,積累足夠的業務場景,積累足夠的常見問題後,再回過頭來細細研究這三個特性。

方法的重寫(override),指的是子類重寫(覆寫)父類的方法。要求方法簽名要保持一緻,不能抛出更多的異常(封裝),不能有更加嚴格的通路權限(多态)。

方法的重載(overload),指的是在同一個類或者子類中來重載一個方法,兩個方法之間要求參數清單不能相同,而其他的要相同。這是為了能夠有多個過程類似的方法實作的。

接口可以了解為是一種規範、标準、協定,而并不關心具體實作過程。接口中的方法隻能使用public、abstract來修飾,而屬性隻能是用public、static、final來修飾。換句話說,在接口中即使不添加任何修飾符也可以,因為它隻能添加那些修飾符——方法必然是public abstract的,而屬性一定是public static final的。根據接口中屬性的特點,我們可以推斷,在申明屬性變量時必須給賦初始值,而且不能被修改。

如果有人要問,在接口的方法上添加abstract或者不添加有沒有差別的話,從上文就可以推斷出——是一樣的。對應的屬性也是這個道理。

普通類中,所有的方法必須要有方法體——也就是說必須要有實作,同樣的方法不可以使用abstract來修飾。類隻允許繼承一個類,但是可以實作多個接口。類a實作類b,可以了解為類a也是一種b;而類a實作接口b、c,則可以了解為類a有b和c的特性(特點)。

而抽象類,就像是接口和普通類的結合體,方法既可以有抽象的(abstract)的,也可以沒有。對屬性則沒有任何限制。另外,由于抽象類中有可能有抽象方法,是以是無法直接進行執行個體化的。

這是必須要弄明白的,在日常工作中跟它打交道的次數太多了。首先是java.util.collection這個接口,它是集合的頂層接口,另外要留心它所在的包(package)是java.util。它的子接口包括list、set,list的實作類包括:arraylist、linkedlist、vector。set的實作類包括:hashset、linkedhashset、treeset。

arraylist的内部是用動态數組(普通數組的容量必須在初始化時給定)實作的,根據數組下标來對元素進行操作,具有通路快速、修改較慢的特點,這些是由于arraylist的存儲結構導緻的。如果調用無參構造函數的話,會把内部數組elementdata指派一個空數組;如果調用的是帶有一個int類型參數(容量capacity)的構造函數的話,會建立一個指定大小的數組。在調用add方法時,會先檢查目前數組是否可以在容納一個元素(這時候,保證至少會有10的容量),如果不夠的話就準備擴容(最大容量為integer.max_value)——先是建立一個新容量的數組,然後把之前的元素拷貝過去,最後把要添加的元素加入新的數組中。

根據以上arraylist類的特點,我們可以總結出一些arraylist的使用技巧:如果您估計arraylist中要添加的元素個數超過10個的話,最好調用有int參數的構造函數給定一個初始容量,這樣能有效地避免頻繁擴容導緻的頻繁申請記憶體(堆),甚至能避免一些不必要的gc事件;arraylist适合讀取和修改操作較多的場合,而不适合于添加或者删除較多的場合;arraylist并沒有實作了多線程之間的同步,是以是線程不安全的。

可以通過工具類java.util.collections的sort方法給list排序。

通過collections的binarysearch來快速地查找list中的元素。

linkedlist<e>實作的是雙向連結清單(doubly-linked),另外還實作了接口java.util.deque<e>。它有add、addfirst、addlast、addall等方法,add等同于addlast,set方法可以添加到指定位置。調用get方法時,它會從所有的元素中周遊查找。是以,linkedlist和arraylist相反,插入、新增速度快,查找速度慢。另外,它也是線程不安全的。

vector<e>除了實作了list接口外還實作了java.util.randomaccess接口,預設的容量為10,内部也是用數組的形式實作的。它的add以及其他操作元素的方法使用了關鍵字synchronized,是以是線程安全的,也可以認為vector是線程安全版本的arraylist。

treeset<e>内部是利用treemap實作的,調用add方法時其實就是向map中添加一條key,value的值統一都是object類。

hashset<e>内部是利用hashmap實作的。add方法實作過程與treeset類似。

java集合體系中的java.util.map比較特殊,和collection不是一類,它本身就是頂層接口。它的實作類包括:hashmap、hashtable。

hashmap<k,v>預設的構造函數會初始化一個容量(應該是2的倍數,最大容量為integer.max_value / 2 + 1,或者為1 << 30)為10、因子(load factor)為0.75的集合,之後調用init方法(預設為空實作,是讓子類來擴充的)。

hashmap第一次調用put方法時,内部會調用方法inflatetable來初始化,是以說如果隻是申明了一個map對象後并不會占用任何空間。從這裡可以看到hashmap内部也是通過數組實作的,數組的元素類型為hashmap.entry;而entry類包含了key、value、下一個entry的引用、hash值。而當key為null時,則内部會調用方法putfornullkey,把key為null的entry會放到數組的第一個。這時候會通過hash方法來計算key的hash值,hash方法會先調用key對象的hashcode,然後再進行一些hash運算。之後利用hash值和數組的長度計算出來一個數組下标值,如果數組中的該下标(index)中已經有了entry對象,則從entry鍊中通過hash查找是否已經存在了相同的key,有的話更新;沒有的話,則新增一個entry放到數組的該下标中,然後該entry指向之前的entry,形成一個entry鍊。

從上面對hashmap的分析,可以得出一些結論。它内部是由多個元素類型為hashmap.entry的數組實作,是以占用的記憶體空間還是比較大的。key可以為null。它從java1.6開始出現,是非線程安全的。

hashtable實作了抽象類dictionary<k,v>。它從java1.0開始出現。它的初始化過程和hashmap類似,但初始容量(capacity)為11,因子(load factor)為0.75f。

hashtable的put方法使用關鍵字(synchronized)保證了線程間的同步,當key或者value為空(null)時會抛出空指針異常。

treemap<k,v>實作了接口navigablemap<k,v>。該集合和hashmap實作的過程類似,隻是在調用put方法時就會先對key進行排序。這個排序就要求key實作接口comparator<? super k>,或者是在執行個體化treemap時給定一個comparator。

navigablemap<k,v>該接口繼承了接口sortedmap<k,v>,從java1.6開始出現。

java中的“流”相關内容都在包java.io中,想要系統的了解java流就要知道有哪些分類。

按照大的類型分為:輸入流(inputstream)和輸出流(outputstream)。這兩個頂層的流都是用抽象類來表示的,它們規定了輸入、輸出流的基本方法,它們是基于位元組(byte)流。

java.lang.readable和java.lang.appendable是另一對java“流”接口。注意這兩接口在java.io中對應的頂層抽象類分别為:reader、writer,它們是針對字元類型的流。

datainput和dataoutput是java“流”中的面向資料類型的輸入、輸出流。

所有類型的輸入、輸出流都實作了接口closeable,它隻有一個close方法,那這個close方法應該由誰來調用呢,我這裡有個建議——誰打開的“流”誰來關閉。

java的異常體系的根類是java.lang.throwable,它有兩個子類java.lang.error和java.lang.exception。

error是比較嚴重的錯誤,基本會在程式無法繼續執行的情況下抛出,我們無法捕獲更無法處理。

exception是“編譯時”異常的根類,它的子類java.lang.runtimeexception是“運作時”異常。所謂編譯時指的是在編譯java源檔案時抛出的異常,必須在處理(捕獲或者抛出)後源檔案才可以正常編譯;所謂運作時異常,指的是在java程式運作過程中有“可能”抛出的異常。

除了error之外,編譯時異常也是比較嚴重的異常情況,是以必須顯示地處理。而運作時異常通常不嚴重,即遇到了這種異常情況程式也還是可以繼續的。

實作一個多線程類,可以實作接口java.lang.runnable或者類java.lang.thread。這裡要注意的是類thread也實作了接口runnable。啟動一個線程要調用start方法,如下例子所示:

線程間同步,可以在類或者方法上使用關鍵字synchronized。

另外,還有個線程相關的知識點。使用thread.sleep和object.wait相比較,前者會一直占用cpu,而後者會放棄cpu的控制權。

有關java多線程的更多内容請搜尋“java多線程”。

好多人都在談論“設計模式”,還有一些人可以說出很多種設計模式,例如:單例模式、工廠模式、觀察者模式等等。但對于剛剛進入這個行業的人來說,我不認為記住這麼多的名稱有任何用處,而且在實際項目中也不會有實踐的機會。學習設計模式這是一件長期的事情,而且在有一定項目程式設計經驗以後再來學習會更有效果。

我在這裡先介紹一個很容易了解的設計模式——單例模式。所謂單例,指的是在虛拟機(jvm)中某個類隻有一份執行個體。通常情況下,單例的實作有幾個需要注意的地方:構造函數私有化、提供一個靜态方法用于擷取執行個體對象、考慮多線程情況。

在java中所有的都是類,而所有java.lang.object類則是所有類的父類——即使沒有“顯示地”繼承。而jdk中有些類是用來描述“類本身”資訊的,它們大多數在包java.lang.reflect中,例如:method、field、constructor、member、type、modifier等。

而我這裡提到的反射就是jdk提供的用于擷取“類本身”資訊的api,換句話說:通過反射技術可以動态第擷取甚至修改“類本身”的資訊。如果你對c語言有點了解的話,這一點可以和c語言的指針來做對比了解。

那麼反射技術通常都用在什麼場合呢?利用反射可以做到很多正常程式無法做到的事情,例如代理,而在架構設計中經常會用到反射技術。

jdk中提供的用于程式設計gui(使用者界面)程式的是swing架構。這裡的api都是在java.awt和javax.swing中,我們可以認為javax.swing包中的api是對java.awt中api的更新或者改進。例如,按鈕的實作類button就有兩份,分别是java.awt.button和javax.swing.jbutton。從包的分布和類名上,我們可以看到差別,在javax.swing包中的元件類基本都是大寫字母j開頭的。這裡,我推薦使用javax.swing包中的api。

java是跨平台的,由此提供的swing架構也是在所有的平台上運作時可以保持一緻的風格。但由此引發的一個問題是:利用swing編寫的gui程式(c/s架構)相對比較醜陋一點,導緻在企業開發中用的相對比較少。但是,利用swing來開發一些小的工具還是完全可以的。

這裡我介紹一些gui程式原理性的内容,這樣你就算沒寫過也可以多少有點了解。所有的gui程式的底層都是在調動api在螢幕上“繪制圖形”,是以呢,可以了解gui程式中會有一個單獨的線程來做“繪制”工作,而且這個線程就是主線程。然後,我們繼續思考,如果一個界面中的元件(元素)過多的話,就會導緻“繪制”線程占用的時間比較多,使用起來顯得比較“卡”。

既然上面我已經提到了線程,那麼在程式中讀取、處理資料時占用的時間比較長的話,就會導緻界面更加“卡”。為了解決這個問題,我們通常都會選擇新開一個線程來處理占用時間比較長的任務。到此為止呢,我們至少已經有了兩個線程,那麼在讀取、處理資料的線程中要修改界面元素的話,就必然涉及到了線程間同步的問題——我們不可以在新的線程中修改界面元素,否則會發生資料不同步的問題。

java網絡程式設計是很大的一塊内容,現在呢,您隻需要了解java網絡程式設計中都有哪些接口(功能),以及簡單了解網絡協定即可。

tcp/ip協定棧分為應用層、傳輸層、鍊路層等。java提供了傳輸層協定的網絡程式設計接口,也就是可以對tcp、udp協定資料包進行操作。而應用層的網絡協定,例如:ftp、http、sftp、snap等都需要利用第三方的庫了。httpclient即是apache的一個子項目,用于操作http協定。

tcp協定是可靠的協定,它能保證資料包完整地在網絡中進行傳輸,而udp協定則不能保證這一點,但udp傳輸的速度相對比較快。據此特點,udp經常用在需要傳輸大量資料,但對資料完整性要求不是很高的場合,例如視訊傳輸等。另外,tcp在發送資料包時,必須要求對方正在簡體你指定的端口,否則無法發送;而udp協定則不需要對方一定是正在監聽中,它隻管發送,不關心對方是否已經接收了。

jsp(java server pages)作為常用的一種動态頁面技術,有幾個很關鍵的地方是必須了解清楚、正确的,這也是作為一個合格、稱職、專業的程式員所應該了解的。

首先,從jsp的字面上來說,它一定是伺服器端(後端)的技術,而不是前端技術,不可以和html混為一談。和其他的動态頁面技術不同,它是需要編譯的——當它被通路時,将會由jsp引擎編譯(class位元組碼檔案);如果是在tomcat中運作的話,編譯後的位元組碼檔案會儲存在目錄work/catalina/localhost/${webroot}/org/apache/jsp中。

那jsp編譯完的class檔案是什麼呢?從它所繼承(實作)的類上看,就能一目了然了。它繼承了類org.apache.jasper.runtime.httpjspbase,實作了接口org.apache.jasper.runtime.jspsourcedependent。

而httpjspbase是個抽象類,它繼承了抽象類javax.servlet.http.httpservlet,實作了接口javax.servlet.jsp.httpjsppage。

接口jspsourcedependent是為了能夠跟蹤jsp源碼檔案的依賴關系,進而能夠編譯過期的jsp檔案。

這裡至少應該知道如何使用jquery定位元素、設定(擷取)值、ajax請求。

jquery有類(class)選擇器、名稱(tagname)選擇器、id選擇器、屬性(attribute)選擇器、派生選擇器等。

本站有一篇《javascript調試介紹》您可以搜尋一下,介紹了各種主流浏覽器的javascript調試方法和技巧。

本站有一篇《eclipse使用技巧》您可以搜尋一下,介紹了eclipse的一些使用技巧。

本章有一篇《玩轉tomcat》您可以搜尋一下,介紹了tomcat所有常用的配置方法。

除了要會使用資料庫的帶有界面的用戶端(例如:navicat等)連接配接,還需要知道如何通過指令行來連接配接,例如:mysql -uroot -proot。

建立資料庫(database)、表(table)的sql應該會寫,簡單的查詢語句更是必須的。

本站有幾篇有關hibernate的專題介紹,大家可以搜尋一下《hibernate注解類介紹》、《hibernate常見異常》。

<a href="http://surenpi.com/2016/06/20/java_dev_path_first_year/">java開發成長之路第一年</a>

<a href="http://surenpi.com/2016/07/07/java_dev_path_second_year/">java開發成長之路第二年</a>

<a href="http://surenpi.com/2016/07/07/java_dev_path_third_year/">java開發成長之路第三年</a>

<a href="http://surenpi.com/2016/07/07/java_dev_path_fourth_year/">java開發成長之路第四年</a>

<a href="http://surenpi.com/2016/07/07/java_dev_path_fifth_year/">java開發成長之路第五年</a>

<a href="http://surenpi.com/2016/07/11/java_dev_path_sisth_year/" target="_blank">java開發成長之路第六年</a>

<a href="http://surenpi.com/2017/02/16/java_dev_path_seventh_year/" target="_blank">java開發成長之路第七年</a>