叮!您收到一份超值Java基礎入門資料!

摘要:Java語言有什麼特色?如何最大效率的學習?深淺拷貝到底有何區別?阿里巴巴高級開發工程師爲你們帶來Java系統解讀,帶你掌握Java技術要領,突破重點難點,入門面向對象編程,以詳細示例帶領你們Java基礎入門!

本次直播視頻精彩回顧, 戳這裏

演講嘉賓簡介:

邢凱航(花名:弗止),阿里巴巴Java高級開發工程師,香港大學計算機科學碩士,16年加入阿里巴巴,目前就任於研發效能事業部用戶聲音及代碼智能化團隊,負責代碼中心後端開發。
html


如下內容根據演講嘉賓視頻分享以及PPT整理而成。

本文將圍繞一下幾個方面進行介紹:
1. Java語言特色
2. 如何學習Java
3. JVM概述
4. 面向對象入門
5. 示例演示
6. 擴展閱讀

一. Java語言特色

1. Java是一種面向對象的語言,以對象爲顆粒度,對象中包含屬性和方法,經過對象間的繼承和組合構建程序世界。在學習面嚮對象語言時,你們不只僅應該關注過程,還須要對待解決的問題進行抽象和建模,最終生成易於維護和擴展的設計方案。這是一個由淺入深、按部就班的過程。
算法

2. 其次,Java具備良好的跨平臺特性。Java程序能夠不受計算機硬件和操做系統的約束,在任何支持Java虛擬機(JVM)的環境下均可以正常運行。編寫的Java程序通過編譯後生成的字節碼能夠被JVM識別,JVM爲程序運行屏蔽了底層操做系統的差別。

3. 第三個特色是Java具備垃圾回收機制,簡稱GC(Garbage Collection)。在Java中不須要關心內存空間的回收問題,這一切都會交給JVM進行處理。JVM會識別出哪些對象不須要再次被使用,進而自動回收其內存空間,不須要手動回收,大大提升了開發效率。
編程

4. 第四個特性是Java爲單根結構。Java中全部的類都繼承成自同一個基礎類object,如此全部類具備同一個通用接口,而且在層次結構上都屬於同一類型,這爲編程提供了極大的便利。

5. 另外Java在設計之初就很是注重安全性,在多個階段均提供了安全保證。Java中不支持指針,避免了非法內存的操做。在編譯運行時,提供了多重語法、類型、邊界和字節碼的檢查。
後端

6. 最後Java語言是解釋型的語言。Java編譯的結果並不會在操做系統上運行,而是生成一箇中間class文件,被JVM加載並解釋執行。早期的Java版本由於解釋過程,運行速度相比C++要慢不少,但隨着Java編譯器的優化,某些結果甚至已經代表Java會比C++運行更快,所以現在並無統一的定論。
安全


二. 如何學習Java

首先,Java的學習有兩條主線——Java語言和JVM。一方面,你們須要學習Java語言編程的語法規則,可以熟練使用JDK提供的經常使用的工具類,並經過多線程解決問題。此外還須要熟練掌握一至兩個框架,快速上手工程的開發。另外一方面,你們須要瞭解JVM底層,瞭解Java內部的運行機制。其次,關於工具的選擇,這裏推薦你們使用在業界比較流行的IntelliJ IDEA或Eclipse。一個好的編程工具會提供不少優秀的能力,提高開發效率。第三點,建議你們使用較新的JDK版本,例如JDK8及以上。JDK在更新過程當中會出現一些優秀的類庫以及新的語法規則,及時更新版本有助於跟上業界新步伐。最後尤其重要的是須要多看、多思考、多實踐。多看一些優秀的源碼和工程,例如JDK源碼,能夠了解好的編碼習慣和風格,而且經過熟悉底層的原理,有助於寫出高性能和健壯的程序;再例如Tomcat源碼,阿里Dubbo源碼等,從中學習軟件設計思惟。最後還須要多練習實踐。數據結構

三. JVM概述

1. Java內存區域管理
多線程

Java內存區域包括兩部分:由全部線程共享的數據區和線程隔離的數據區,如圖所示:
7ec0476df1fcf4dbf3a31ece952fd16e1e5014ea
在線程隔離的數據區中,包括虛擬機棧、本地方法棧和程序計數器。程序計數器能夠指示當前線程所執行的字節碼的行號,字節碼解釋器會經過更改計數器的值來選取下一條須要執行的字節碼指令。每一個線程的程序計數器都是獨立的,確保各線程間計數器互不影響。虛擬機棧也是線程私有的,生命週期和線程相同,每一個方法執行時會建立一個棧針、當前執行方法的局部變量表、操做數、動態連接、方法出口等信息都存儲在該區域中。方法的調用和返回對應的棧針在虛擬機棧中的入棧和出棧操做中。本地方法棧的做用與虛擬機棧相似,不過本地方法棧存儲的是調用native方法時使用的數據結構。方法區是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量和靜態變量等數據。堆也是共享內存區域,存儲對象實例、JVM的垃圾回收等。

2. 垃圾回收

Java的垃圾回收機制中,首先須要肯定哪些對象須要進行垃圾回收,這裏一般採用可達性分析來進行判斷。這個算法的基本思想是設置一系列對象做爲起點,稱爲GC Roots節點,搜索創建引用鏈,當一個對象到GC Roots沒有任何引用鏈相連時,則證實此對象是不可用的。在進行可達性分析時,須要讓整個系統凍結在某個時間點,對外則表現爲全部工做進程都中止,如此才能夠準確獲取全部GC Roots,這個過程稱爲stop the world。此外,引用計數器算法也能夠判斷對象是否存活,雖然該算法效率較高,但若是存在對象間的循環引用,即便這些對象不可訪問,也存在沒法回收的狀況。
框架

在回收對象實例時,有多種算法可供選擇。第一種標記-清除算法,分爲兩個階段,首先標記出全部須要回收的對象,而後統一進行回收。第二種複製算法,針對方法一中內存碎片過多的缺點,複製算法將內存按照容量劃分爲大小相同的兩塊,每次只使用其中的一塊,當一塊用完後,將仍存活的對象複製到另外一塊中,而後將使用的那塊空間一次性清理,如此反覆使用。第三種標記-整理算法,針對方法二中內存利用率不高的缺點進行改進,過程和方法一相似,首先對對象進行標記,而後將仍存活的對象向一端移動,而後清理邊界之外的內存區域。方法四分代收集算法,將堆劃分爲新生代和老年代,根據對象的生命週期,分別放入不一樣的內存區域中,同時針對不一樣垃圾回收特色的對象採用不一樣的回收策略。新生代分爲一塊較大的Eden區和兩個較小的survival區,由於新生代大部分對象都須要回收,因此採用複製算法進行回收。而老年代中須要回收的對象較少,所以採用標記-清除或者標記-整理算法進行回收。基於上述垃圾回收算法,JVM實現了多個垃圾收集器,能夠經過一些參數進行設定(具體內容可參考擴展閱讀)。

四. 面向對象入門

在Java語言中,全部類都擁有一個共同的父類Object,即使沒有顯式聲明。接下來展現Object的一些方法,以下圖所示:
函數

1327753269f53471f8f5a02f20fce211b45c5b3c
首先,它包含一個private方法refisterNatives(),該方法與本地註冊有關,這裏不作詳細討論。其次,它包含notify()和notifyAll()方法,這兩種方法比較相似,歸併爲一類,另包含三種wait()方法,也歸爲一類。所以Object類共包含8種方法,分爲如下四類進行講解。
0bd3d58f99f09dcb8ce7e673890405962ce0c926
他們分別回答了四個問題:我是誰,我從哪裏來,我到哪裏去,我與外界如何互相做用的。getClass和hashCode分別讓外界知曉當前對象的類型和一個獨一無二的標識。equals告訴外界當前對象是否和另外一個對象相等。toString用字符串標識當前對象信息。clone方法可讓外界得到當前對象的一個拷貝。finalize方法能夠實現對象被回收前最後的清理工做。notify()和notifyAll()方法用於喚醒一個等待在該對象上的一個線程或全部線程。wait方法是讓當前線程進入等待狀態,直至被喚醒或者等待時間結束。注意這裏clone方法和finalize方法使用灰色表示,由於兩者都屬於protected方法,若是需使用則須要重寫其實現。另外在重寫clone還要注意深拷貝和淺拷貝的問題,finalize方法使用時具備不肯定性,這裏不推薦你們使用。

五. 示例演示

1. 總體示例
工具

在類Phone中,定義了兩個屬性brand和serialNum,表明品牌和序列號。在構造函數中,爲兩個屬性初始化值。同時實現了clone接口,覆蓋了父類實現。

76aa1c7db946cf6d45f9c699cd6519176bb9318c
在main函數中,定義了phone1和phone2,phone2是phone1的拷貝,而後打印出兩個變量的基本信息,包括手機的類名稱、hashCode、表示當前手機的字符串和對比兩個手機是否相同。運行結果以下所示:
f74a0c2be690c70c0c91e288ea5631abcb7e519c
ec1917e9eab0580fe362e237625693fa49bce86f
由運行結果可見,兩者屬於同一個類,但hashCode不一樣,而且字符串表示也不相同。接下來仔細介紹每一個方法。hashCode方法爲native,代表調用的本地方法,代碼由非Java代碼寫出。hashCode返回一個int數值,表明內存空間中的一個地址。
da97116b088a578237d5af4a9bbf006428f9b676
equals方法以下所示,用雙等號來對比兩個對象,注意由於此處兩變量都爲引用類型,所以這裏雙等號對比的是兩者引用的內存地址是否一致。上例中由打印出的hashCode可見兩者內存地址不一致,所以equals方法返回false。
2d05553a7cb1a60f75f0729f73fe38266be82e34
toString方法中,首先打印類名稱,加上@,還有內存地址空間的十六進制表示。

943c95c3558526faef5ff4d2b1b72c1839dc1799

但某些狀況下咱們認爲若是phone的品牌和序列號一致即爲兩者一致,此時便須要嘗試修改一些方法的實現。這裏可使用IDE工具自動生成generate的部分代碼(具體操做詳見視頻),以下所示:

79451cda2e45d78dc519fe3ca9bb5a7b88ddb650

此時在equals中,首先比較兩者的內存地址空間,若是一致返回true;若不一致則進一步比較兩者的類信息,若類不一致,則返回false,若一致,則須要繼續比較其屬性值,若屬性值都一致,則能夠認爲兩者是相同的對象。hashCode中也相似,使用其兩個屬性值生成hashCode。

f025e9a7f65faf10d2dca5fa462a4c11e74ee7b9

相似的也能夠生成toString的實現,使用StringBuffer類來拼接字符串,打印出相關屬性值。此時再運行主函數,得出結果以下:

e467ef85bcf20e73fd6ec9d06382e1c545e8b12c

此時兩個變量的hashCode值已經一致,用字符串表示時也會打印出一些屬性信息,對比結果也返回true。

2. 深淺拷貝示例

類Screen中,包含屬性值size,表示屏幕大小。而且有getSize方法獲取屏幕大小以及setSize方法設置size。toString方法將size值打印出來。

84fc54671bfac04521fcbbcfea95481ab61faccb
接着在上例Phone類中加入屬性值Screen,而且更新構造函數,加入獲取和更新屏幕的方法,以下所示:
5eee06c330ec4762266e7e8f3276253d9ba5c424
feb0addbdf31157ee5886c59f86df123b8849376
從新編寫main()函數。首先定義了大小爲5的屏幕,phone1和phone2與上例一致,只是phone1新增了參數變量screen。分別打印出兩個phone的屏幕大小,而後更改screen的值,再打印一次,運行結果以下所示:

da8489c8c671211b06161639659103cbecbf7517

b953c4d32c14b9ee650ec53922412e9e18ca3dee
由結果可見,在更改screen大小以前,兩個phone的屏幕大小都爲5,更改完成後都變爲6。這代表此處默認的clone方法實現的爲淺拷貝。由於screen中存儲的爲內存地址空間,拷貝後的對象存儲的依然是該地址,所以改變屏幕size時兩者同時變化。下面展現深拷貝,代碼如圖所示:

10f4cf5dac0a33c1809e229814ad7aac7dc03562

首先從super.clone中得到phone變量,爲其從新設置屏幕大小,設置的值爲調用當前screen的clone方法,最後返回變化後的拷貝。運行結果以下所示:

cd75aa032887c23470b953d65b88c9c9db6f76a1

此時能夠看到在第二次更改完size以後,只有phone1的屏幕大小變爲6,而phone2的屏幕大小仍然爲以前的值。

六. 擴展閱讀
48a6b0e7829f56a0eab0bcf9e05b2cbee3c69c97

數十款阿里雲產品限時折扣中,趕忙點擊這裏,領劵開始雲上實踐吧!


文章做者: 聒小小噪

原文連接

本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索