码出高效
碼出高效
- 一.計(jì)算機(jī)基礎(chǔ)
- 1.1 0和1的世界
- 原碼,反碼,補(bǔ)碼
- 為什么出現(xiàn)反碼,補(bǔ)碼
- 位運(yùn)算
- 1.2 浮點(diǎn)數(shù)
- 1.3 字符集與亂碼
- 1.4 CPU與內(nèi)存
- 1.5 TCP/IP
- 1.6 信息安全
- 二.面向?qū)ο?/li>
- 2.1 OOP理念
- 2.2 初識Java
- 2.3 類
- 2.4 方法
- 三.代碼風(fēng)格
- 3.1 命名規(guī)約
- 3.1.1 常量
- 3.1.2 變量
- 3.2 代碼展示風(fēng)格
- 3.2.1 縮進(jìn),空格與空行
- 3.2.2 換行與高度
- 3.2.3 控制語句
- 四 走進(jìn)JVM
- 4.1 字節(jié)碼
- 4.2 類加載過程
- 4.3 內(nèi)存布局
- 4.4 對象實(shí)例化
- 4.5 垃圾回收
- 異常與日志
- 5.1 異常分類
- 5.2 try 代碼塊
- 5.3 異常的接與拋
- 5.4 日志
- 5.4.1 日志規(guī)范
- 5.4.2 日志框架
一.計(jì)算機(jī)基礎(chǔ)
1.1 0和1的世界
原碼,反碼,補(bǔ)碼
原碼就是符號位加上真值的絕對值, 即用第一位表示符號, 其余位表示值.
反碼的表示方法是:
正數(shù)的反碼是其本身
負(fù)數(shù)的反碼是在其原碼的基礎(chǔ)上, 符號位不變,其余各個位取反.
補(bǔ)碼的表示方法是:
正數(shù)的補(bǔ)碼就是其本身
負(fù)數(shù)的補(bǔ)碼是在其原碼的基礎(chǔ)上, 符號位不變, 其余各位取反, 最后+1. (即在反碼的基礎(chǔ)上+1)
為什么出現(xiàn)反碼,補(bǔ)碼
將符號位參與運(yùn)算, 并且只保留加法的方法. 首先來看原碼:
計(jì)算十進(jìn)制的表達(dá)式: 1-1=0
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
為了解決原碼做減法的問題, 出現(xiàn)了反碼:
計(jì)算十進(jìn)制的表達(dá)式: 1-1=0
1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
發(fā)現(xiàn)用反碼計(jì)算減法, 結(jié)果的真值部分是正確的. 而唯一的問題其實(shí)就出現(xiàn)在"0"這個特殊的數(shù)值上. 雖然人們理解上+0和-0是一樣的, 但是0帶符號是沒有任何意義的. 而且會有[0000 0000]原和[1000 0000]原兩個編碼表示0.
補(bǔ)碼的出現(xiàn), 解決了0的符號以及兩個編碼的問題:
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]補(bǔ) + [1111 1111]補(bǔ) = [0000 0000]補(bǔ)=[0000 0000]原
位運(yùn)算
<<左移 >>右移 >>>無符號右移
在左移<<與右移>>兩種運(yùn)算中,符號位均參與移動,除負(fù)數(shù)往右移動,高位補(bǔ)l 之外,其他情況均在空位處補(bǔ)0
左移運(yùn)算由于符號位參與向左移動,在移動后的結(jié)果中,最左位可能是1 或者0,
即正數(shù)向左移動的結(jié)果可能是正,也可能是負(fù),負(fù)數(shù)向左移動的結(jié)果同樣可能是正,
也可能是負(fù)
對于三個大于號的>>〉無符號向右移動(注意不存在<<<無符號向左移動的運(yùn)
算方式),當(dāng)向右移動時(shí),正負(fù)數(shù)高位均補(bǔ)0 ,正數(shù)不斷向右移動的最小值是0 ,而
負(fù)數(shù)不斷向右移動的最小值是l
為何負(fù)數(shù)不斷地?zé)o符號向右移動的最小值是l 呢?在實(shí)際編程中,位移運(yùn)算僅作
用于整型(32 位)和長整型(64 位)數(shù)上,假如在整型數(shù)上移動的位數(shù)是32 位,無
論是否帶符號位以及移動方向,均為本身。因?yàn)橐苿拥奈粩?shù)是個mod 32 的結(jié)果,
即35 >> 1 與3 5 ?33 是一樣的結(jié)果
1.2 浮點(diǎn)數(shù)
從數(shù)字時(shí)間的科學(xué)計(jì)數(shù)法映射到計(jì)算機(jī)世界的浮點(diǎn)數(shù)是,數(shù)值從十進(jìn)制改為二進(jìn)制,還要考慮內(nèi)存硬件設(shè)備的實(shí)現(xiàn)方式.在規(guī)格化表示上存在差異,稱謂有所改變,指數(shù)稱為"階碼",有效數(shù)字稱為"尾數(shù)",所以用戶存儲符號,階碼,尾數(shù)的二進(jìn)制位分別稱為符號位,階碼位,尾數(shù)位.
在最高二進(jìn)制位上分配l 位表示浮點(diǎn)數(shù)的符號,0 表示正數(shù),1 表示負(fù)數(shù)。
在符號位右側(cè)分配8 位用來存儲指數(shù),
最右側(cè)分配連續(xù)的23 位用來存儲有效數(shù)字,
加減運(yùn)算
在數(shù)學(xué)中,進(jìn)行兩個小數(shù)的加減運(yùn)算時(shí),首先要將小數(shù)點(diǎn)對齊,然后同位數(shù)進(jìn)行
加減運(yùn)算。對兩個采用科學(xué)計(jì)數(shù)法表示的數(shù)做加減法運(yùn)算時(shí),為了讓小數(shù)點(diǎn)對齊就需
要確保指數(shù)一樣。當(dāng)小數(shù)點(diǎn)對齊后,再將有效數(shù)字按照正常的數(shù)進(jìn)行加減運(yùn)算。
在要求絕對精確表示的業(yè)務(wù)場景下,比如金融行業(yè)的貨幣表示,推薦使用整型存
儲其最小單位的值,展示時(shí)可以轉(zhuǎn)換成該貨幣的常用單位,比如人民幣使用分存儲,
美元使用美分存儲。在要求精確表示小數(shù)點(diǎn)n 位的業(yè)務(wù)場景下,比如圓周率要求存儲
小數(shù)點(diǎn)后1000 位數(shù)字,使用單精度和雙精度浮點(diǎn)數(shù)類型保存是難以做到的,這時(shí)推
薦采用數(shù)組保存小數(shù)部分的數(shù)據(jù)。在比較浮點(diǎn)數(shù)時(shí),由于存在誤差,往往會出現(xiàn)意料
之外的結(jié)果,所以禁止通過判斷兩個浮點(diǎn)數(shù)是否相等來控制某些業(yè)務(wù)流程。在數(shù)據(jù)庫
中保存小數(shù)時(shí),推薦使用decimal 類型,禁止使用float 類型和double 類型。因?yàn)檫@
兩種類型在存儲的時(shí)候,存在精度損失的問題。
1.3 字符集與亂碼
在ASCII 碼中,有兩個特殊的控制字符10 和13 ,前者是LF 即“\n ”,后者是
CR 即V”,在編碼過程中,代碼的換行雖然是默認(rèn)不可見的,但在不同的操{乍系統(tǒng)中’
表示方式是不樣的。在UNIX 系統(tǒng)中,換行使用換行符“\n,在window系統(tǒng)中,
換行使用"\r\n;在舊版macOS中,換行符使用回車符"/r",在新版macOS中使用
與UNIX 系統(tǒng)豐目同的換行方式。前編碼環(huán)境使用換行方式是LF ,
這也是推薦的換行方式,避免出現(xiàn)源碼在不同操作系統(tǒng)中換行顯示不同的情況。
1.4 CPU與內(nèi)存
CPU ( Central Processing Unit )是一塊超大規(guī)模的集成電路板,是計(jì)算機(jī)的核心
部件,承載著計(jì)算機(jī)的主要運(yùn)算和控制功能,是計(jì)算機(jī)指令的最終解釋模塊和執(zhí)行模
塊。硬件包括基板、核心、針腳,基板用來固定核心和針腳,針腳通過基板上的基座
連接電路信號,CPU 核心的工藝極度精密,達(dá)到10 納米級別。CPU 的內(nèi)部結(jié)
構(gòu)如圖 所示。
內(nèi)存物理結(jié)構(gòu)由內(nèi)存芯片、電路板、控制芯片、相關(guān)支持模塊等組成,內(nèi)
存芯片結(jié)構(gòu)比較簡單,核心是存儲單元,支持模塊是地址譯碼器和讀寫控制器,如圖所示。
1.5 TCP/IP
TCP/IP ( Transmission Control Protocol I Internet Protocol )中文譯為傳輸控制協(xié)
議/因特網(wǎng)互聯(lián)協(xié)議,這個大家族里的其他知名協(xié)議還有HTTP, HTT陀、FTP、
SMTP、UDP, ARP、PPP、IEEE 802.x 等。TCP/IP 是當(dāng)前流行的網(wǎng)絡(luò)傳輸協(xié)議框架,
從嚴(yán)格意義上講它是一個協(xié)議族,因?yàn)門CP, IP 是其中最為核心的協(xié)議,所以就把
該協(xié)議族稱為TCP/IP
IP協(xié)議
IP是面向無連接、無狀態(tài)的,沒有額外的機(jī)制保證發(fā)送的包是否有序到達(dá)。IP
首先規(guī)定出IP 地址格式,該地址相當(dāng)于在邏輯意義上進(jìn)行了網(wǎng)段的劃分,給每臺計(jì)
算機(jī)額外設(shè)置了一個唯一的詳細(xì)地址。既然鏈路層可以通過唯一的MAC 地址找到機(jī)
器,為什么還需要通過唯的IP 地址再來標(biāo)識呢?簡單地說,在世界范圍內(nèi),不可
能通過廣播的方式,從數(shù)以千萬計(jì)的計(jì)算機(jī)里找到目標(biāo)MAC 地址的計(jì)算機(jī)而不超時(shí)。
連接池
在客戶端與服務(wù)端之間可以事先創(chuàng)建若干連接并提
前放置在連接池中,需要時(shí)可以從連接池直接獲取,數(shù)據(jù)傳輸完成后,將連接歸還至
連接池中,從而減少頻繁創(chuàng)建和釋放連接所造成的開銷。例如,RPC 服務(wù)集群的注冊
中心與服務(wù)提供方、消費(fèi)方之間,消息服務(wù)集群的緩存服務(wù)器和消費(fèi)者服務(wù)器之間,
應(yīng)用后臺服務(wù)器和數(shù)據(jù)庫之間,都會使用連接池來提升性能。
1.6 信息安全
黑客與與安全
現(xiàn)代黑客攻擊的特點(diǎn)是分布式、高流量、深度匿名
互聯(lián)網(wǎng)企業(yè)都要建立一
套完整的信息安全體系,遵循CIA 原則,即保密性(Confidentiality ) ,完整性(Integrity ),可用性(Availability )
- 保密性。對需要保護(hù)的數(shù)據(jù)(比如用戶的私人信息等)進(jìn)行保密操作,無論
是存儲還是傳輸,都要保證用戶數(shù)據(jù)及相關(guān)資源的安全。比如,在存儲文件
時(shí)會進(jìn)行加密,在數(shù)據(jù)傳輸中也會通過各種編碼方式對數(shù)據(jù)進(jìn)行加密等。 - 完整性。訪問的數(shù)據(jù)需要是完整的,而不是缺失的或者被篡改的,不然用戶
訪問的數(shù)據(jù)就是不正確的。比如,在商場看中一個型號為NB 的手機(jī),但售
貨員在包裝的時(shí)候被其他人換成了更便宜的型號為LB 的于機(jī),這就是我們
所說的資源被替換了,也就是不滿足完整性的地方。在實(shí)際編寫代碼中,一
定要保證數(shù)據(jù)的完整性,通常的做法是對數(shù)據(jù)進(jìn)行簽名和校驗(yàn)(比如MDS
和數(shù)字簽名等)。 - 可用性。服務(wù)需要是可用的。如果連服務(wù)都不可用,也就沒有安全這-說了。
比如還是去商場買東西,如果有人惡意破壞商場,故意雇用大量水軍在商場
的收銀臺排隊(duì),既不結(jié)賬也不走,導(dǎo)致其他人無法付款,這就是服務(wù)已經(jīng)不
可用的表現(xiàn)。這個例子和常見的服務(wù)拒絕(Dos )攻擊十分相似。對于這種情況,
通常使用訪問控制、限流等手段解決。
SQL注入
( I )過濾異戶輸入?yún)?#xff06;中的阿彌字符,從而降低被SQL ,t入的風(fēng)險(xiǎn)。
( 2 )禁止通過字符南拼撞的SQL i吾旬,嚴(yán)恪使用參數(shù)綁定傳人的SQL 參數(shù)c
( 3 )合理使月數(shù)據(jù)庫擊可框豆、提供的防左入機(jī)制。
XSS
XSS 跨站腳本攻擊,即
Cross-Site Scripting ,為了不幸日前端開發(fā)中層疊樣式表(css )的名字沖突,簡稱為
XSSa XSS 是指黑客通過技術(shù)手段,向正常用戶請求的HTML 頁面中插入惡意腳本,
從而可以執(zhí)行任意腳本。
在防范xss 上,主要通過對用戶輸入數(shù)據(jù)做過濾或者轉(zhuǎn)義。比如Java 開發(fā)人
員可以使用Jsoup 框架對用戶輸入字符串做xss 過濾,或者使用框架提供的工具
類對用戶輸入的字符串做HTML 轉(zhuǎn)義,例如Spring 框架提供的HtmlUtils 。前端在
瀏覽器展示數(shù)據(jù)時(shí),也需要使用安全的API 展示數(shù)據(jù),比如使用innerText 而不是
innerHTML 。所以需要前、后端開發(fā)人員一同配合才能有效防范xss 漏洞。
CSRF
跨站請求偽造(Cross-Site Request Forgery ),簡稱CSRF ,也被稱為One-click
Attack , !l.D 在用戶并不知惰的情況下,冒充用戶發(fā)起請求,在當(dāng)前已經(jīng)登錄的Web 應(yīng)
用程序上執(zhí)行惡意操作,如惡意發(fā)帖、修改密碼、發(fā)郵件等。
xss 是在正常用戶請求的HTML 頁面中執(zhí)行了黑客提供的惡意代碼,
cs 盯是黑客直接盜用用戶瀏覽器中的登錄信息,冒充用戶去執(zhí)行黑客指定的操作。
xss 問題出在用戶數(shù)據(jù)沒有過濾、轉(zhuǎn)義l cs 盯問題出在HTTP 接口沒有防范不受信
任的調(diào)用。
防范CSRF 漏洞主要通過以下方式,
( I ) CSRF Token 驗(yàn)證,利用瀏覽器的同源限制,在HTTP 接口執(zhí)行前驗(yàn)證頁面
或者Cookie 中設(shè)置的Token ,只有驗(yàn)證通過才繼續(xù)執(zhí)行請求。
( 2 )人機(jī)交互,比如在調(diào)用上述網(wǎng)上銀行轉(zhuǎn)賬接口時(shí)校驗(yàn)短信驗(yàn)證碼。
HTTPS
( I )瀏覽器向服務(wù)器發(fā)送請求,請求中包括瀏覽器支持的協(xié)議,并附帶一個隨
機(jī)數(shù)。
( 2 )服務(wù)器收到請求后,選擇某種非對稱加密算法,把數(shù)字證書簽有公鑰、身
份信息發(fā)送給瀏覽器,同時(shí)也附帶一個隨機(jī)數(shù)。
( 3 )瀏覽器收到后、驗(yàn)證證書的真實(shí)性,用服務(wù)器的公鋁發(fā)送握手信息給服務(wù)器。
( 4 )服務(wù)器解密后,使用主前的隨機(jī)數(shù)計(jì)算出,個對稱加密的密鑰,以此作為
加密信息并發(fā)送。
( 5 )后續(xù)所有的信息發(fā)送都是以對稱加密方式進(jìn)行的。
二.面向?qū)ο?/h2>
2.1 OOP理念
面向過程讓計(jì)算機(jī)有步驟地順次做件事情,是種過程化的敘事思維。但是在
大型軟件開發(fā)過程中,發(fā)現(xiàn)用面向過程語言開發(fā),軟件維護(hù)、軟件復(fù)用存在著巨大的
困難,代碼開發(fā)變成了記流水賬,久而久之就成為“面條”代碼,模塊之間互相輯合,
流程互相穿插,往往牽發(fā)而動全身。面向?qū)ο筇岢鲆环N計(jì)算機(jī)世界里解決復(fù)雜軟件
工程的方法論,拆解問題復(fù)雜度,從人類思維角度提出解決問題的步驟和方案。
2.2 初識Java
Java 語言擁有跨平臺、分布式、多線程、健壯性等主要特點(diǎn),是當(dāng)下比較主流的
高級編程語言。它的類庫相當(dāng)豐富、功能強(qiáng)大、簡單易用,對開發(fā)者相當(dāng)友好,不僅
吸收了C++的優(yōu)點(diǎn),還摒棄了其難以掌控的多繼承、指針等概念。Java 比較好地實(shí)
現(xiàn)了面向?qū)ο罄碚?#xff0c;允許開發(fā)工程師以優(yōu)雅的思維方式處理復(fù)雜的編程場景。
2.3 類
類的定義
類的定義由訪問級別、類型、類名、是否抽象、是否靜態(tài)、泛型標(biāo)識、繼承或?qū)?br /> 現(xiàn)關(guān)鍵字、父類或接口名稱等組成。類的訪問級別有public 和無訪問控制符,類型分
為class 、interface 、en um 。
接口與抽象類
正如面向?qū)ο笏拇筇匦?#xff08;抽象、封裝、繼承、多態(tài))所述,定義類的過程就是抽
象和封裝的過程,而接口與抽象類則是對實(shí)體類進(jìn)行更高層次的抽象,僅定義公共行
為和特征。接口與抽象類的共同點(diǎn)是都不能被實(shí)例化,但可以定義引用變量指向?qū)嵗龑ο?br />
內(nèi)部類
在個.java 源文件中,只能定義一個類名與文件名完全致的公開類,使用
public class 關(guān)鍵字來修飾。但在面向?qū)ο笳Z言中1 任何一個類都可以在內(nèi)部定義另外
一個類,前者為外部類,后者為內(nèi)部類。內(nèi)部類本身就是類的一個屬性,與其他屬性
定義方式一致。
- 靜態(tài)內(nèi)部類,如static class StaticinnerC!ass {} ;
- 成員內(nèi)部類,如:private class InstancelnnerC!ass {} ;
- 局部內(nèi)部類,定義在方法或者表達(dá)式內(nèi)部,
- 匿名內(nèi)部類,如:(new Thread(){} ).start()。
訪問權(quán)限控制
面向?qū)ο蟮暮诵乃枷胫痪褪欠庋b,只把有限的方法和成員公開給別人,這也是
迪米特法則的內(nèi)在要求,使外部調(diào)用方對方法體內(nèi)的實(shí)現(xiàn)細(xì)節(jié)知道得盡可能少
在定義類時(shí),推薦訪問控制級別從嚴(yán)處理.
( I )如果不允許外部直接通過new 創(chuàng)建對象,構(gòu)造方法必須是pnvale 。
( 2 )工具類不允許有p u b l ic 或default 構(gòu)造方法。
( 3 )類非s t a t ic 成員變雪并且與子類共享,必須是protected 。
( 4 )類非stat i c 成員變量并且僅在本類使用,必須是private 。
( 5 )類stat i c 成員變量如果僅在東類使用,必須是private o
( 6 )若是stat i c 成員變量,必須考慮是否為final o
( 7 )類成員方法只供類內(nèi)部調(diào)用,必須是private 。
( 8 )類成員方法只對繼承類公開,那么限制為protected
this與super
對象實(shí)例化時(shí),至少有條從本類出發(fā)抵達(dá)0 均ect 的通路,而打通這條路的兩
個主要工兵就是thi s 和s uper
類關(guān)系
有關(guān)系的
情況下,包括如下5 種類型,
- [繼承]extends (is-a )。
- [實(shí)現(xiàn)]implements (can-do)。
- [組合]類是成員變量(contai ns - a )。
- {聚合}類是成員變量(has-a)。
- [依賴]import 類(use-a )
序列化
( I ) Java 原生序列化
Java 類通過實(shí)現(xiàn)Serializable 接口來實(shí)現(xiàn)該類對象的序列化,
這個接口非常特殊,沒有任何方法,只起標(biāo)識作用。Java 序列化保留了對象類的元數(shù)
據(jù)(如類、成員變量、繼承類信息等),以及對象數(shù)據(jù)等,兼容性最好,但不支持跨
語言,而且性能一般
實(shí)現(xiàn)Seri alizable 接口的類建議設(shè)置seria!VersionUID 字段值,如果不設(shè)置,那么
每次運(yùn)行時(shí),編譯器會根據(jù)類的內(nèi)部實(shí)現(xiàn),包括類名、接口名、方法和屬性等來自
動生成seria!Version UID 。如果類的源代碼有修改,那么重新編譯后seria!VersionUID
的取值可能會發(fā)生變化。因此實(shí)現(xiàn)Serializable 接口的類一定要顯式地定義
seria!Version UID 屬性值。修改類時(shí)需要根據(jù)兼容性決定是否修改serialVersionUID 值
- 如果是兼容升級,請不要修改seria!VersionUID 字段,避免反序列化失敗。
- 如果是不兼容升級,需要修改serialVersionUID 值,避免反序列化混亂。
使用Java 原生序列化需注意,Java 反序歹lj化時(shí)不會調(diào)用類的無參構(gòu)造方法,而
是調(diào)用native 方法將成員變量賦值為對應(yīng)類型的初始值。基于性能及兼容性考慮,不
推薦使用Java 原生序列化
( 2 ) Hessian 序列化。
Hessian 序列化是一種支持動態(tài)類型、跨語言、基于對象
傳輸?shù)木W(wǎng)絡(luò)協(xié)議。Java 對象序列化的二進(jìn)制流可以被其他語言(如C++、Python )反
序列化。Hessian 協(xié)議具有如下特性.
- 自描述序列化類型。不依賴外部描述文件或接口定義,用一個字節(jié)表示常用基礎(chǔ)類型,極大縮短二進(jìn)制流。
- 語言無關(guān),支持腳本語言。
- 協(xié)議簡單,比Java 原生序列化高效。
相比Hessian 1.0, Hessian 2.0 中增加了壓縮編碼,其序列化二進(jìn)制流大小是Java
序列化的50% ,序列化耗時(shí)是Java 序列化的30 % ,反序列化耗時(shí)是Java 反序列化的
20%
Hessian 會把復(fù)雜對象所有屬性存儲在一個Map 申進(jìn)行序列化。所以在父類、子
類存在同名成員變量的情況下,Hessian 序列化時(shí),先序列化子類,然后序列化父類,
因此反序列化結(jié)果會導(dǎo)致子類同名成員變量被父類的值覆蓋。
3 ) JSON 序列化
JSON ( JavaScript Object Notation )是一種輕量級的數(shù)據(jù)交
換格式。JSON 序列化就是將數(shù)據(jù)對象轉(zhuǎn)換為JSON 字符串。在序列化過程中拋棄了
類型信息,所以反序列化時(shí)只有提供類型信息才能準(zhǔn)確地反序列化。相比前兩種方式,
JSON 可讀性比較好,方便調(diào)試
2.4 方法
方法簽名
方法簽名包括方法名稱和參數(shù)列表,是NM 標(biāo)識方法的唯一索引,不包括返回值,
更加不包括訪問權(quán)限控制符、異常類型等。
參數(shù)
方法簽名包括方法名稱和參數(shù)列表,是NM 標(biāo)識方法的唯一索引,不包括返回值,
更加不包括訪問權(quán)限控制符、異常類型等。
無論是對于基本數(shù)據(jù)類型,還是引用變量,Java 中的參數(shù)傳遞都是值
復(fù)制的傳遞過程。對于引用變量,復(fù)制指向?qū)ο蟮氖椎刂?#xff0c;雙方都可以通過自己的引
用變量修改指向?qū)ο蟮南嚓P(guān)屬性。
構(gòu)造方法
構(gòu)造方法(Constructor )是方法名與類名相同的特殊方法,在新建對象時(shí)調(diào)用,
可以通過不同的構(gòu)造方法實(shí)現(xiàn)不同方式的對象初始化,它有如下特征,
( I )構(gòu)造1J 沽名稱必示與吳兵相同。
( 2 )均圭方江主二沒有返國類在二吶,即使是void tli,-懷能有z 它返回對象的地址,
并賦值給引用變量。
( 3 )枯l z 丁、-t: 吉~ t … ,’ .(…’ T 市被ff 弓. -.T ‘i「妒土I’" 調(diào)用途徑有三種
一是通過new 關(guān)鍵字,二是在子類的構(gòu)造方法中通過super 調(diào)用父類的構(gòu)造方法,三
是通過反射方式獲取并使用。
( 4 )吳王飛jj fo~ +「J 認(rèn)-~ ._送去均王元、去但是如果顯式定義了有參構(gòu)造方法,
則此無參構(gòu)造方法就會被覆蓋,如果依然想擁有,就需要進(jìn)行顯式定義。
( 5 )均生于1 、主以和平外部無法使用私有構(gòu)造方法創(chuàng)建對象。
類內(nèi)方法
除構(gòu)造方法外,類中還可以有三類方法實(shí)例方法、
靜態(tài)方法、靜態(tài)代碼塊。
getter與setter
在實(shí)例方法中有類特殊的方法,即ge憂er 與se憂er 方法,它們一般不包含任何
業(yè)務(wù)邏輯,僅僅是為類成員屬性提供讀取和修改的方法,這樣設(shè)計(jì)有兩點(diǎn)好處I
(!)滿足面向?qū)ο笳Z言封裝的特’生。盡可能將類中的屬性定義為private ,針對
屬性值的訪問與修改需要使用相應(yīng)的getter 與se位er 方法,而不是直接對public 的屬
性進(jìn)行讀取和修改。
( 2 )有利于統(tǒng)一控制。雖然直接對屬性進(jìn)行讀取、修改的方式和使用相應(yīng)的
getter 與se憂er 方法在效果上是一樣的,但是前者難以應(yīng)對業(yè)務(wù)的變化。
同步與異步
同步調(diào)用是因剛性調(diào)用,是阻塞式操作,必須等待調(diào)用方法體執(zhí)行結(jié)束。而異步調(diào)
用是柔性調(diào)用,是非阻塞式操作,在執(zhí)行過程中,如調(diào)用其他方法,自己可以繼續(xù)執(zhí)
行而不被阻塞等待方法調(diào)用完畢。
覆寫
多態(tài)中的overri de ,本書翻譯成覆寫。如果翻譯成重寫,那么與重構(gòu)意思過于
接近;如果翻譯成覆蓋,那么少了“寫”這個核心動詞。
方法的覆寫可以總結(jié)成容易記憶的口訣“一大兩小兩同”。
- 一大子類的方法訪問權(quán)限控制符只能相同或變大。
- 兩小,拋出異常和返回值只能變小,能夠轉(zhuǎn)型成父類對象。子類的返回值、
拋出異常類型必須與父類的返回值、拋出異常類型存在繼承關(guān)系。 - 兩同i 方法名和參數(shù)必須完全相同。
重載
在同一個類中,如果多個方法有相同的名字、不同的參數(shù),即稱為重載,比如一
個類中有多個構(gòu)造方法。JVM在重載方法中,選擇合適的目標(biāo)方法的順
序如下
泛型
泛型的本質(zhì)是類型參數(shù)化,解決不確定具體對象類型的問題。在面向?qū)ο缶幊陶Z
言中,允許程序員在強(qiáng)類型校驗(yàn)下定義某些可變部分,以達(dá)到代碼復(fù)用的目的。
- 尖捂號里的每個元素都指代一種未知類型。
- 尖括號的位置非常講究,必須在類目之后或方法返回值之前
- 泛型在定義處只具備執(zhí)行Object方法的能力
- 對于編譯之后的字節(jié)碼指令,其實(shí)沒有這些花頭花腦的方法簽名,充分說明泛型只是一種編寫代碼時(shí)的語法檢查
數(shù)據(jù)類型
I )對象頭(Object !leader )
對象頭占用12 個字節(jié),存儲內(nèi)容包括對象標(biāo)記(markOop )和類元信息(klassOop )。
對象標(biāo)記存儲對象本身運(yùn)行時(shí)的數(shù)據(jù),如哈希碼、GC 標(biāo)記、鎖信息、線程關(guān)聯(lián)信息等,
這部分?jǐn)?shù)據(jù)在64 位NM 上占用8 個字節(jié),稱為"Mark word",為了存儲更多的狀
態(tài)言息,對象標(biāo)記的存儲恪式是非固定的(具休與JVM 的實(shí)現(xiàn)有關(guān))。類元信患、存
儲的是對象指向它的類元數(shù)據(jù)(即Kl ass )的首地址’占用4 個字節(jié),與refvar 開銷一致。
( 2 )實(shí)例數(shù)據(jù)(Instance Data )
存儲本類對象的實(shí)例成員變量和所有可見的父類成員變量。如Integer 的實(shí)例
成員只有一個private int value ,占用4 個字節(jié),所以加上對象頭為16 個字節(jié)1 再
如,上述示例代碼的R巳fObjDemo 對象大小為48 個字節(jié),一個子類RefObjSon 繼承
RefObjDemo ,即使子類內(nèi)部是空的,n ew RefObjSon 的對象也是占用48 個字節(jié)。
( 3 )對齊填充(Padding )
對象的存儲空間分配單位是8 個字節(jié),如果一個占用大小為16 個字節(jié)的對象,
增加一個成員變量byte 類型,此時(shí)需要占用17 個字節(jié),但是也會分配24 個字節(jié)進(jìn)
行對齊填充操作。
包裝類型
( I ) 所有的POJO 類屬性必須使用包裝數(shù)據(jù)類型
( 2 ) RPC 方法的返回值和參數(shù)必須使用包裝數(shù)據(jù)類型。
( 3 )所有的局部變量推薦使用基本數(shù)據(jù)類型。
字符串
字符串相關(guān)類型主要有三種String 、Strin gBuild 町、Strin gBuffer 。String 是只讀
字符串,典型的immutabl e 對象,對它的任何改動,其實(shí)都是創(chuàng)建一個新對象,再把
引用指向該對象。Strin g 對象賦值操作后,會在常量池中進(jìn)行緩存,如果下次申請創(chuàng)
建對象時(shí),緩存中已經(jīng)存在,貝lj直接返回相應(yīng)引用給創(chuàng)建者。而StringBuffer 貝lj 可以
在原對象上進(jìn)行修改,是線程安全的。JDK5 號|入的Str i ngBuilder 與StringBuffer 均繼
承自AbstractStringBui Ider ,兩個子類的很多方法都是通過飛uper . 方法。”的方式調(diào)
用抽象父類中的方法,此抽象類在內(nèi)部與String 一樣,也是以字符數(shù)組的形式存儲字
符串的。StringBuilder 是非線程安全的,把是否需要進(jìn)行多線程加鎖交給工程師決定,
操作效率比StringBuffer 高。線程安全的對象先產(chǎn)生是因?yàn)橛?jì)算機(jī)的發(fā)展總是從單線
程到多線程,從單機(jī)到分布式。
三.代碼風(fēng)格
3.1 命名規(guī)約
- 包名統(tǒng)使用小寫,點(diǎn)分隔符之間有且僅有個自然語義的英語單詞。包名
統(tǒng)一使用單數(shù)形式,但是類名如果有復(fù)數(shù)含義,則可以使用復(fù)數(shù)形式。 - 抽象類命名使用Abstract 或Base 開頭;異常類命名使用Exception 結(jié)尾,測
試類命名以它要測試的類名開始,以Test 結(jié)尾。 - 類型與中括號緊挨相連來定義數(shù)組。
- 枚舉類名帶上Enum 后綴,枚舉成員名稱需要全大寫,單詞間用下畫線隔開
3.1.1 常量
- 采用字母全部大寫、單詞之間加下畫線的方式。而局部常量采用小駝峰形式即可。
- 避免魔法值,幾乎是固定不變的全局常量采用枚舉,普通常量采用不能實(shí)例化的抽象類
3.1.2 變量
變量的命名需要滿足小駝峰格式,命名體現(xiàn)業(yè)務(wù)含義即可。存在一種特殊情況,在定義類成員變量時(shí),特別是在POJO 類中,針對布爾類型的變量,命名不要加is 前綴,否則部分框架解析會引起序列化錯誤。
3.2 代碼展示風(fēng)格
3.2.1 縮進(jìn),空格與空行
采用4 個空恪的縮進(jìn)方式
( I )任何二目,三目運(yùn)算符的左右兩邊都必須加一個空格.
( 2 )注釋的雙斜線與注釋內(nèi)容之間有且僅有一個空恪。
( 3 )方法參數(shù)在定義和傳入時(shí),多個參數(shù)逗號后面必須加空格。
( 4 )沒有必要增加若干空格使變量的賦值等號與上一行對應(yīng)的位置的等號對齊
( 5 )如果大括號內(nèi)為空,則可以簡寫成{}即可, 大括號中間無需換行和空格
( 6 )左右小括號與括號內(nèi)部的相鄰字符之間不要出現(xiàn)空格.
( 7 ) 左大括號前需要加空格
空行用來分隔功能相似、邏輯內(nèi)聚、意思相近的代碼片段,使得程序布局更加清
晰
3.2.2 換行與高度
約定單行字符數(shù)不超過120 個,超出則需要換行,換行時(shí)遵循如下原則:
( I )第二行相對第一行縮進(jìn)4個空格,從第三行開始,不再繼續(xù)縮進(jìn),參考示例。
( 2 )運(yùn)算符與下文一起換行。
( 3 )方法調(diào)用的點(diǎn)符號與下文一起換行。
( 4 )方法調(diào)用中的多個參數(shù)需要換行時(shí),在逗號后換行。
( 5 )在括號前不要換行。
約定單個方法的總行數(shù)不超過80 行
3.2.3 控制語句
四 走進(jìn)JVM
4.1 字節(jié)碼
Java 所有的指令有200 個左右,一個字節(jié)(8 位)可以存
儲256 種不同的指令信息,一個這樣的字節(jié)稱為字節(jié)碼(Bytecode )。在代碼的執(zhí)行
過程中,NM 將字節(jié)碼解釋執(zhí)行,屏蔽對底層操作系統(tǒng)的依賴l NM 也可以將字節(jié)
碼編譯執(zhí)行,如果是熱點(diǎn)代碼,會通過刀T 動態(tài)地編譯為機(jī)器碼,提高執(zhí)行效率
4.2 類加載過程
第一步,Load 階段讀取類文件產(chǎn)生二進(jìn)制流,并轉(zhuǎn)化為特定的數(shù)據(jù)結(jié)構(gòu),初步
校驗(yàn)cafe babe 魔法數(shù)、常量池、文件長度、是否有父類等,然后創(chuàng)建對應(yīng)類的java.
Jang.Class 實(shí)例。
第二步,Link 階段包括驗(yàn)證、準(zhǔn)備、解析三個步驟。驗(yàn)證是更詳細(xì)的校驗(yàn),比
如final 是否合規(guī)、類型是否正確、靜態(tài)變量是否合理等i 準(zhǔn)備階段是為靜態(tài)變量分
配內(nèi)存,并設(shè)定默認(rèn)值,解析類和方法確保類與類之間的相互引用正確性,完成內(nèi)存
結(jié)構(gòu)布局。
第三步,Init 階段執(zhí)行類構(gòu)造器<clinit> 方法,如果賦值運(yùn)算是通過其他類的靜
態(tài)方法來完成的,那么會馬上解析另外個類,在虛擬機(jī)槍中執(zhí)行完畢后通過返回值
進(jìn)行賦值。
4.3 內(nèi)存布局
Heap 是OOM 故障最主要的發(fā)源地,它存儲著幾乎所有的實(shí)例對象,堆由垃圾
收集器自動回收,堆區(qū)由各子線程共享使用。通常情況下,它占用的空間是所有內(nèi)存
區(qū)域中最大的,但如果無節(jié)制地創(chuàng)建大量對象,也窯易消耗完所有的空間。堆的內(nèi)存
空間既可以固定大小,也可以在運(yùn)行時(shí)動態(tài)地調(diào)整,通過如下參數(shù)設(shè)定初始值和最大
值,比如-Xms256M -Xmxl024M ,其中-X 表示它是JVM 運(yùn)行參數(shù),ms 是memory
start 的簡稱,mx 是memory max 的簡稱,分別代表最小堆窯量和最大堆窯量。
早在JDK8版本中,無空間的前身Perm 區(qū)已經(jīng)被淘汰。在JDK7 及之前的版本中,只有Hotspot
才有Perm 區(qū),譯為永久代,它在啟動時(shí)固定大小,很難進(jìn)行調(diào)優(yōu),并且FGC 時(shí)會移
動類無信息。在某些場景下,如果動態(tài)加載類過多,容易產(chǎn)生Perm 區(qū)的OOM 。
區(qū)別于永久代,元空間在本地內(nèi)存中分配。在JDK8 里,Perm 區(qū)中的所有內(nèi)容
中字符串常量移至堆內(nèi)存,其他內(nèi)容包括類元信息、字段、靜態(tài)屬性、方法、常量等
都移動至無空間內(nèi),比如圖4-10 中的0均ect 類元信息、靜態(tài)屬性System.out 、整型
常量10000000 等。圖4-10 中顯示在常量池中的Strir 氈,其實(shí)際對象是被保存在堆內(nèi)
存中的。
棧(Stack )是-個先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),就像子彈的彈夾,最后壓入的子彈先發(fā)射,
壓在底部的子彈最后發(fā)射,撞針只能訪問位于頂部的那一顆子彈。
本地方法棧(Native Method Stack )在JVM 內(nèi)存布局中,也是結(jié)程對象私有的,
但是虛擬機(jī)棧“主內(nèi)”,而本地方法棧“主外”。
每個線程在創(chuàng)建后,都會產(chǎn)生自己的程序計(jì)數(shù)器和枝幀,程序計(jì)數(shù)器用來存放執(zhí)行指令的偏移量和行號指示器等,線程執(zhí)行或恢復(fù)都要依賴程序計(jì)數(shù)器。程序計(jì)數(shù)器在各個線程之間互不影響,此區(qū)域也不會發(fā)生內(nèi)存溢出異常。
最后,從線程共享的角度來看,堆和元空間是所有線程共享的,而虛擬機(jī)枝、本
地方法枝、程序計(jì)數(shù)器是線程內(nèi)部私有的,從這個角度看下Java 內(nèi)存結(jié)構(gòu),如圖4-12
所示。
4.4 對象實(shí)例化
4.5 垃圾回收
Java 會對內(nèi)存進(jìn)行自動分配與回收管理,使上層業(yè)務(wù)更加安全,方便地使用內(nèi)存
實(shí)現(xiàn)程序邏輯。在不同的口爪4 實(shí)現(xiàn)及不同的回收機(jī)制中,堆內(nèi)存的劃分方式是不一
樣的,垃圾回收的主要目的是清除不再使用的對象,自動釋放內(nèi)存。
異常與日志
5.1 異常分類
JDK 中定義了套完整的異常機(jī)制,所有異常都是Throwable 的子類,分
為Error (致命異常)和Exception (非致命異常)。Error 是一種非常特殊的異
常類型,它的出現(xiàn)標(biāo)識著系統(tǒng)發(fā)生了不可控的錯誤,例如StackOverflowError 、
OutO島1 emoryEηor 。針對此類錯誤,程序無法處理,只能人工介入。Exception 又分
為ch ecked 異常(受檢異常)和unchecked 異常(非受檢異常)。
5.2 try 代碼塊
try-catch-finally 是處理程序異常的三部曲。當(dāng)存在try 時(shí),可以只有catch 代碼塊,
也可以只有finally 代碼塊,就是不能單獨(dú)只有try 這個光桿司令。
5.3 異常的接與拋
契約式編程理念就完全處于防御式編程理念的下風(fēng),
所以我們推薦方法的返回值可以為null ,不強(qiáng)制返回空集合或者空對象等,但是必須
添加注釋充分說明什么情況下會返回null 值。防止NP E 定是調(diào)用方的責(zé)任,需要
調(diào)用方進(jìn)行事先判斷。
5.4 日志
記錄應(yīng)用系統(tǒng)曰志主要有三個原因記錄操作軌跡、監(jiān)控系統(tǒng)運(yùn)行狀況、
回溯系統(tǒng)故障。
5.4.1 日志規(guī)范
應(yīng)用中的擴(kuò)展日志命名方式應(yīng)該有統(tǒng)-
的約定,通過命名能直觀明了地表明當(dāng)前日志文件是什么功能,如監(jiān)控、訪問日志
等。推薦的日志文件命名方式為appName_logType logName.log 。其中,log Type 為
日志類型,推薦分類有stats 、monitor 、visit 等,logNam e 為日志描述。這種命名的
好處是通過文件名就可以知道曰志文件屬于什么應(yīng)用,什么類型,什么目的,也有利
于歸類查找。例如,mppserv er 應(yīng)用中單獨(dú)監(jiān)控時(shí)區(qū)轉(zhuǎn)換異常的日志文件名定義為
mppserver monitor timeZoneConvert.log 。
代碼規(guī)約推薦曰志文件至少保存1 5 天,可以根據(jù)日志文件的重要程度、
文件大小及磁盤空間再自行延長保存時(shí)間。
5.4.2 日志框架
日志框架分為三大部分,包括日志門面、曰志適配器、日志庫。
門面設(shè)計(jì)模式是面向?qū)ο笤O(shè)計(jì)模式中的一種,日志框架采用的就是這種模式,類
似JDB C 的設(shè)計(jì)理念。它只提供一套接口規(guī)范,自身不負(fù)責(zé)日志功能的實(shí)現(xiàn),目的是
讓使用者不需要關(guān)注底層具體是哪個日志庫來負(fù)責(zé)日志打印及具體的使用細(xì)節(jié)等。目
前用得最為廣泛的曰志門面有兩種slf4j 和commons -logging 。
它具體實(shí)現(xiàn)了日志的相關(guān)功能,主流的日志庫有三個,分別是log4j 、log -jdk 、
logback 。最早Java 要想記錄曰志只能通過System.out 或System.err 來完成,非常不方便。
log4j 就是為了解決這一問題而提出的,它是最早誕生的曰志庫。接著JD K 也在1 .4 版
本引入了一個日志庫java. util.logging. Logger.,簡稱log-dk。這樣市面上就出現(xiàn)兩種日志
功能的實(shí)現(xiàn),開發(fā)者在使用時(shí)需要關(guān)注所使用的日志庫的具體細(xì)節(jié)。logback 是最晚出
現(xiàn)的,它與log4j 出自同一個作者,是log4j的升級版且本身就實(shí)現(xiàn)了slf4j的接口。
曰志適配器分兩種場景
( I )日志門面適配器,因?yàn)閟lf4j規(guī)范是后來提出的此之前的日志庫是沒有
實(shí)現(xiàn)slf4j的接口的,例如log4j ;所以在工程里要想使用slf4j +log4j 的模式,就額
外需要個適配器(slf4j-log4j12 來解決接口不兼容的問題。
( 2 )日志庫適配器,在一些老的工程里,一開始為了開發(fā)簡單而直接使用了日志庫API來完成曰志打印,隨著時(shí)間的推移想將原來直接調(diào)用日志庫的模式改為業(yè)界標(biāo)準(zhǔn)的門面模式(例如slf4j +logback 組合),但老工程代碼里打印曰志的地方太多,難以改動,所以需要個運(yùn)隊(duì)器來完成從舊日志庫的API 到slf4j 的路由,這樣在不改動原有代碼的情況l、也能使用slf4j叫來統(tǒng)一管理曰志,而日后續(xù)自由替換具體日志庫也不成可題。
總結(jié)
- 上一篇: c#让电脑锁定、注销、关机
- 下一篇: 云南干旱 谁人受损 心有戚戚 愤怒哀