-
接口/抽象類意義
- 規(guī)范、擴展呆贿、回調(diào)
- 為其子類提供一個公共的類型 封裝子類中得重復內(nèi)容 定義抽象方法嚷兔,子類雖然有不同的實現(xiàn) 但是定義是一致的
- 接口更多的是在系統(tǒng)架構(gòu)設計方法發(fā)揮作用,主要用于定義模塊之間的通信契約做入、而抽象類在代碼實現(xiàn)方面發(fā)揮作用,可以實現(xiàn)代碼的重用同衣,例如竟块,模板方法
-
多態(tài)的理解
- 表現(xiàn):
- 多態(tài)性是指允許不同子類型的對象對同一消息作出不同的響應
- 多態(tài)性分為編譯時的多態(tài)性和運行時的多態(tài)性,方法重載(overload)實現(xiàn)的是編譯時的多態(tài)性(也稱為前綁定)耐齐,而方法重寫 (override)實現(xiàn)的是運行時的多態(tài)性(也稱為后綁定)術為動態(tài)綁定浪秘,具體就是父類的引用指向子類的對象
- 實現(xiàn)多態(tài)需要做兩件事:
- 方法重寫(子類繼承父類并重寫父類中已有的或抽象的方法)
- 對象造型(用父類型引用引用子類型對象,這樣同樣的引用調(diào)用同樣的方法就會根據(jù)子類對象的不同而表現(xiàn)出不同的行為)
- 優(yōu)點:
- 可擴張性好埠况,無論添加多少個子類耸携,基類的接口都不用改變,只需要在子類對應方法中提供具體實現(xiàn)即可辕翰,也就是所謂的將程序變化的部分和程序保持不變的部分分離
- 運行時多態(tài)性是面向?qū)ο蟪绦蛟O計代碼重用的一個最強大機制
- 其它規(guī)則:
- 只有正常的方法可以使用多態(tài)夺衍,字段和靜態(tài)方法沒有多態(tài)機制
- 構(gòu)造方法也不支持多態(tài)機制,構(gòu)造方法是隱式的static聲明
- 解析與分派
- 實現(xiàn)原理:
- 當JVM執(zhí)行Java字節(jié)碼時喜命,類型信息會存儲在方法區(qū)中沟沙,為了優(yōu)化對象的調(diào)用方法的速度,方法區(qū)的類型信息會增加一個指針壁榕,該指針指向一個記錄該類方法的方法表矛紫,方法表中的每一個項都是對應方法的指針
- 由于java的單繼承機制,一個類只能繼承一個父類牌里,而所有的類又都繼承Object類颊咬,方法表中最先存放的是Object的方法,接下來是父類的方法,最后是該類本身的方法喳篇。如果子類改寫了父類的方法缓呛,那么子類和父類的那些同名的方法共享一個方法表項
- 由于這樣的特性,使得方法表的偏移量總是固定的杭隙,例如哟绊,對于任何類來說,其方法表的equals方法的偏移量總是一個定值痰憎,所有繼承父類的子類的方法表中票髓,其父類所定義的方法的偏移量也總是一個定值
- 流程:調(diào)用方法時,虛擬機通過對象引用得到方法區(qū)中類型信息的方法表的指針入口铣耘,查詢類的方法表 洽沟,根據(jù)實例方法的符號引用解析出該方法在方法表的偏移量,子類對象聲明為父類類型時蜗细,形式上調(diào)用的是父類的方法裆操,此時虛擬機會從實際的方法表中找到方法地址,從而定位到實際類的方法炉媒。 注:所有引用為父類踪区,但方法區(qū)的類型信息中存放的是子類的信息,所以調(diào)用的是子類的方法表
- 表現(xiàn):
-
抽象類理解
- 抽象方法必須為public或者protected(因為如果為private吊骤,則不能被子類繼承缎岗,子類便無法實現(xiàn)該方法),缺省情況下默認為public白粉。
- 抽象類不能用來創(chuàng)建對象传泊,不能直接實例化,但可以被聲明(程序運行期在內(nèi)存中分配一定空間鸭巴,而抽象類總抽象方法沒有具體的實現(xiàn)方法無法分配具體的內(nèi)存空間)
- 如果一個類繼承于一個抽象類眷细,則子類必須實現(xiàn)父類的抽象方法。如果子類沒有實現(xiàn)父類的抽象方法鹃祖,則必須將子類也定義為為abstract類溪椎。
- 如果一個非抽象類遵循了某個接口,就必須實現(xiàn)該接口中的所有方法惯豆。對于遵循某個接口的抽象類池磁,可以不實現(xiàn)該接口中的抽象方法
- 抽象類可以繼承抽象類、非抽象類楷兽,實現(xiàn)接口
-
抽象類和接口的區(qū)別
- 抽象類是abstract class修飾地熄,接口是interface修飾。
- 抽象類只能單繼承芯杀,接口可以多重實現(xiàn)端考。
- 抽象類和接口所反映的設計理念是不同的,抽象類所代表的是“is-a”的關系,而接口所代表的是“l(fā)ike- a”的關系
- 抽象類可以有任意類型的屬性雅潭,接口成員變量只能是public static final類型的。
- 抽象類可以有普通方法和抽象法方法却特,接口的方法(public abstract修飾)都沒有方法體(普通類實現(xiàn)接口必須全部實現(xiàn)接口方法)
- 抽象類和接口都不能實例化扶供,但是抽象類有構(gòu)造方法,接口沒有構(gòu)造方法裂明。
- 抽象類可以有靜態(tài)代碼塊和靜態(tài)方法椿浓,而接口中不能含有靜態(tài)代碼塊以及靜態(tài)方法
-
類型轉(zhuǎn)換相關
- 自動轉(zhuǎn)換按從低到高的順序轉(zhuǎn)換。不同類型數(shù)據(jù)間的優(yōu)先關系如下:
byte,short,char-> int -> long -> float -> double
- 數(shù)值型變量在默認情況下為Int型闽晦,byte和short型在計算時會自動轉(zhuǎn)換為int型計算扳碍,結(jié)果也是int 型
-
運算中,不同類型的數(shù)據(jù)先轉(zhuǎn)化為同一類型仙蛉,然后進行運算笋敞,轉(zhuǎn)換規(guī)則如下:
- 對于一個final變量,不管它時類變量荠瘪、實例變量夯巷、還是局部變量,只要定義該變量時使用了final修飾哀墓,并在定義該final類變量時指定了初始值趁餐,而且該初始值可以在編譯時被確定下來,那么這個final變量實質(zhì)上已經(jīng)不是變量麸祷,相當于一個恒量或者是直接量
- 自動轉(zhuǎn)換按從低到高的順序轉(zhuǎn)換。不同類型數(shù)據(jù)間的優(yōu)先關系如下:
-
關于String的問題
- 任何類任何包澎怒,值相同的字符串字面常數(shù)(String Literals)都引用同一個對象
- 字面常數(shù)(Literals)就是你寫在源代碼里面的值,比如說int i = 6; 6就是一個整數(shù)形字面常數(shù)阶牍。String s = "abc"; “abc”就是一個字符串字面常數(shù)
- 所有的字符串字面常數(shù)都放在上文提到的字符串池里面,是可以共享的星瘾,eg:String s1 = "abc"; String s2 = "abc"; s1走孽,s2都引用的同一個字符串對象,因此s1==s2
- 字符串字面常數(shù)是Load Class時候?qū)嵗⒎诺阶址乩锩嫒サ?/li>
- 通過常量表達式(constant expressions)計算出來的字符串琳状,也算字符串字面常數(shù)磕瓷,就是說他們也在字符串池中
- 常量表達式編譯時能確定的
-
final String s2 = "a"; String s3 = s2 + "bc";
被final修飾,并且通過常量表達式初始化的變量念逞,也算常量表達式 - 在程序運行時通過連接(+)計算出來的字符串對象困食,是新創(chuàng)建的,他們不是字面常數(shù)翎承,就算他們值相同硕盹,他們也不在字符串池里面,他們在堆內(nèi)存空間里叨咖,因此引用的對象各不相同
- String類的intern方法瘩例,返回一個值相同的String對象啊胶,但是這個對象就像一個字符串字面常數(shù)一樣,意思就是垛贤,他也到字符串池里面去了
-
基本類型焰坪、包裝類、String
- 包裝類提供的xxxValue()方法將包裝類對象轉(zhuǎn)化成基本類型變量
Integer iObj = new Integer(i); int m = iObj.intValue();
- 基本數(shù)據(jù)類型轉(zhuǎn)化為包裝類類型
- 構(gòu)造方法把基本型轉(zhuǎn)成包裝類
- 用valueOf 轉(zhuǎn)成包裝類
- 除Character外所有的包裝類提供parseXXX()方法將特定的字符串轉(zhuǎn)換成基本類型變量
- String類提供了valueOf()方法將基本類型比那里轉(zhuǎn)換成字符串
- 包裝類提供的xxxValue()方法將包裝類對象轉(zhuǎn)化成基本類型變量
-
super關鍵字作用
- super.xxx;(xxx為變量名或?qū)ο竺?:獲取父類中的名字為xxx的變量或方法引用聘惦。使用這種方法可以直接訪問父類中的變量或?qū)ο竽呈危M行修改賦值等操作
- super.xxx();(xxx為方法名):直接訪問并調(diào)用父類中的方法
- super();:調(diào)用父類的初始化方法,其實就是調(diào)用父類中的public xxx()方法
- 子類善绎、父類方法調(diào)用優(yōu)先級由高到低依次為:this.show(O)黔漂、super.show(O)、this.show((super)O)涂邀、super.show((super)O)
-
內(nèi)部類相關
-
作用:
- 內(nèi)部類可以很好的實現(xiàn)隱藏瘟仿,除了該外圍類,其他類都不能訪問
- 在單個外圍類中比勉,可以讓多個內(nèi)部類以不同的方式實現(xiàn)同一個接口劳较,或者繼承同一個類, 彌補在多重繼承上的不足
- 匿名內(nèi)部類可以方便的實現(xiàn)閉包
-
類型:
- 靜態(tài)內(nèi)部類(Static Nested Class):使用static修飾的內(nèi)部類浩聋,當內(nèi)部類中定義靜態(tài)成員观蜗,該內(nèi)部類必須是static,不持有外部類引用衣洁,不依賴外部類(它不能使用任何外圍類的非static成員變量和方法墓捻,只能訪問外部類的靜態(tài)成員)
- 成員內(nèi)部類(Inner Class):就是在某個類的內(nèi)部又定義了一個類,內(nèi)部類所嵌入的類稱為外部類坊夫,成員內(nèi)部類中不能存在任何 static 的變量和方法,可以直接訪問外部類中的成員變量
- 匿名內(nèi)部類:使用new生成的內(nèi)部類砖第,沒有構(gòu)造器,取而代之的是將構(gòu)造器參數(shù)傳遞給超類構(gòu)造器
- 局部內(nèi)部類:不能用訪問控制符环凿、static修飾梧兼,只能訪問被final修飾的局部變量(jdk8可以不用)
-
訪問規(guī)則:
- 內(nèi)部類可以直接訪問外部類成員,外部類要訪問內(nèi)部類智听,必須建立內(nèi)部類對象
- 因為內(nèi)部類的產(chǎn)生依賴于外部類羽杰,持有的引用是類名.this
-
靜態(tài)方法中不能new內(nèi)部類的實例對象?
內(nèi)部類的最重要的一個特點就是它可以直接訪問它外部類的成員變量到推。成員變量是對象身上的考赛。對象創(chuàng)建完成了,才會為成員變量分配空間。能調(diào)用成員變量,意味著一定有了實例對象
關于初始化:
public class Enclosingone { public class InsideOne {} //非靜態(tài)內(nèi)部類 public static class InsideTwo{} //靜態(tài)內(nèi)部類 } class Mytest02{ public static void main(String args []){ Enclosingone.InsideOne obj1 = new Enclosingone().new InsideOne();//非靜態(tài)內(nèi)部類對象 Enclosingone.InsideTwo obj2 = new Enclosingone.InsideTwo();//靜態(tài)內(nèi)部類對象 } }
-
-
重載/重寫
- 方法重載(overload):
- 必須是同一個類
- 方法名(也可以叫函數(shù))一樣
- 參數(shù)類型不一樣或參數(shù)數(shù)量不一樣
- 存在于父類和子類莉测、同類中
- 方法的重寫(override)兩同兩小一大原則:
- 方法名相同颜骤,參數(shù)類型相同
- 子類返回類型小于等于父類方法返回類型,
- 子類拋出異常小于等于父類方法拋出異常悔雹,
- 子類訪問權(quán)限大于等于父類方法訪問權(quán)限复哆。
- 重寫(Overriding)是父類與子類之間多態(tài)性的一種表現(xiàn)(變量不能被重寫)砸捏,而重載(Overloading)是一個類中多態(tài)性的一種表現(xiàn)
- 方法重載(overload):
-
類型&接口
- switch支持類型:byte, short, char, int, 枚舉 ,String(jdk7)
- Java引用類型:類纫普、接口、數(shù)組、枚舉蚤假、注解
- 標志性接口:RandomAccess和Cloneable 软瞎、Serializable不需要任何實現(xiàn)撵孤,只是又來表明其實現(xiàn)類具體有某種特質(zhì)
-
Object方法
- final方法:getClass肆氓、wait、notify久免、notifyAll
- 非final方法:equals浅辙、hashCode、toString阎姥、clone记舆、finalize
-
hashCode() 和equals() 區(qū)別和作用
- 區(qū)別:
- equals(Object obj)方法用來判斷兩個對象是否“相同”,如果“相同”則返回true呼巴,否則返回false
- HashCode的存在主要是為了查找的快捷性泽腮,HashCode是用來在散列存儲結(jié)構(gòu)中確定對象的存儲地址的
- 訪問原理:
- hashcode()方法返回一個int數(shù),在Object類中的默認實現(xiàn)是“將該對象的內(nèi)部地址轉(zhuǎn)換成一個整數(shù)返回(方法集合中用到)
- 對象放入集合時衣赶,首先判斷放入對象的hashcode值與集合中的任意一個元素的hashcode值是否相等诊赊,如果不相等直接將該對象放入集合中。如果hashcode值相等府瞄,然后再通過equals方法判斷要放入對象與集合中的任意一個對象是否相等碧磅,如果equals判斷不相等,直接將該元素放入到集合中遵馆,否則不放入
- 重寫規(guī)則:
- 重寫equals方法時鲸郊,應該要重寫hashcode方法
- 兩者重寫時候關系:
- 如果兩個對象equals,Java運行時環(huán)境會認為他們的hashcode一定相等
- 如果兩個對象不equals货邓,他們的hashcode有可能相等
- 如果兩個對象hashcode相等严望,他們不一定equals
- 如果兩個對象hashcode不相等,他們一定不equals
- 區(qū)別:
-
集合框架圖
-
Java集合框架的基礎接口有哪些逻恐?
- Collection為集合層級的根接口。一個集合代表一組對象峻黍,這些對象即為它的元素复隆。Java平臺不提供這個接口任何直接的實現(xiàn)
- Set是一個不能包含重復元素的集合。這個接口對數(shù)學集合抽象進行建模姆涩,被用來代表集合挽拂,就如一副牌
- List是一個有序集合,可以包含重復元素骨饿。你可以通過它的索引來訪問任何元素亏栈。List更像長度動態(tài)變換的數(shù)組
- Map是一個將key映射到value的對象.一個Map不能包含重復的key:每個key最多只能映射一個value
- 一些其它的接口有Queue台腥、Dequeue、SortedSet绒北、SortedMap和ListIterator
-
為何Collection不從Cloneable和Serializable接口繼承黎侈?
- Collection接口指定一組對象,對象即為它的元素闷游。如何維護這些元素由Collection的具體實現(xiàn)決定峻汉。例如,一些如List的Collection實現(xiàn)允許重復的元素脐往,而其它的如Set就不允許休吠。很多Collection實現(xiàn)有一個公有的clone方法。然而业簿,把它放到集合的所有實現(xiàn)中也是沒有意義的瘤礁。這是因為Collection是一個抽象表現(xiàn)。重要的是實現(xiàn)
- 當與具體實現(xiàn)打交道的時候梅尤,克隆或序列化的語義和含義才發(fā)揮作用柜思。所以,具體實現(xiàn)應該決定如何對它進行克隆或序列化克饶,或它是否可以被克隆或序列化
- 在所有的實現(xiàn)中授權(quán)克隆和序列化酝蜒,最終導致更少的靈活性和更多的限制。特定的實現(xiàn)應該決定它是否可以被克隆和序列化
-
為何Map接口不繼承Collection接口矾湃?
- 盡管Map接口和它的實現(xiàn)也是集合框架的一部分亡脑,但Map不是集合,集合也不是Map邀跃。因此霉咨,Map繼承Collection毫無意義,反之亦然拍屑。
- 如果Map繼承Collection接口途戒,那么元素去哪兒?Map包含key-value對僵驰,它提供抽取key或value列表集合的方法喷斋,但是它不適合“一組對象”規(guī)范
-
HashMap與HashSet的區(qū)別
- HashSet為散列集,其底層采用的是HashMap進行實現(xiàn)的蒜茴,但是沒有key-value(即它不需要Key和Value兩個值)星爪,只有HashMap的key-set的視圖,HashSet不容許重復的對象
- 調(diào)用HashSet的add方法時粉私,實際上是向HashMap中增加了一行(key-value對)顽腾,該行的key就是向HashSet增加的哪個對象,該行的value就是一個Object類型的常量
-
HashMap與TreeMap區(qū)別
- HashMap 通過 hashcode 對其內(nèi)容進行快速查找,而 TreeMap 中所有的元素都保持著某種固定的順 序,如果你需要得到一個有序的結(jié)果你就應該使用 TreeMap(HashMap 中元素的排列順序是不固定的)诺核。Ha shMap 中元素的排列順序是不固定的)抄肖。
- 在 Map 中插入久信、刪除和定位元素,HashMap 是最好的選擇。但如果您要按自然順序或自定義順序遍歷 鍵,那么 TreeMap 會更好漓摩。使用 HashMap 要求添加的鍵類明確定義了 hashCode() 和 equals() 的實現(xiàn)裙士。 這 個 TreeMap 沒有調(diào)優(yōu)選項,因為該樹總處于平衡狀態(tài)
-
HashMap和Hashtable的區(qū)別
- Hashtable繼承自Dictionary類,而HashMap是Java1.2引進的Map interface的一個實現(xiàn)
- Hashtable中key和value都不允許為null幌甘,而HashMap中key和value都允許為null(key只能有一個為null潮售,而value則可以有多個為null)
- Hashtable的方法是Synchronize的,而HashMap不是
- HashTable使用Enumeration進行遍歷锅风,HashMap使用Iterator進行遍歷
- HashTable直接使用對象的hashCode酥诽。而HashMap重新計算hash值
- HashTable中hash數(shù)組默認大小是 11,增加的方式是 old*2+1。HashMap中hash數(shù)組的默認大小是16,而且一定是2的指數(shù)
-
Iterator和Enumeration的區(qū)別
- Enumeration只有2個函數(shù)接口皱埠。通過Enumeration肮帐,我們只能讀取集合的數(shù)據(jù),而不能對數(shù)據(jù)進行修改边器,Iterator只有3個函數(shù)接口训枢,Iterator除了能讀取集合的數(shù)據(jù)之外,也能數(shù)據(jù)進行刪除操作
- Iterator支持fail-fast機制忘巧,而Enumeration不支持
- fail-fast 機制是java集合(Collection)中的一種錯誤機制恒界,當多個線程對同一個集合的內(nèi)容進行操作時,就可能會產(chǎn)生fail-fast事件砚嘴,就會拋出ConcurrentModificationException異常
-
ArrayList和Vector的區(qū)別
- Vector:線程同步十酣,ArrayList:線程不同步,但性能很好
- 當Vector中的元素超過它的初始大小時际长,Vector會將它的容量翻倍耸采,當ArrayList中的元素超過它的初始大小時(默認初始長度為10),ArrayList只增加50%的大小
- 可以用Enumeration接口遍歷
-
Iterator和Iterable區(qū)別
- Iterator是迭代器類工育,而Iterable是接口
- 一個類實現(xiàn)了Iterable虾宇,那么虛擬機就知道,你這個類可以用foreach來循環(huán)
- 集合Collection如绸、List嘱朽、Set都是Iterable的實現(xiàn)類,所以他們及其他們的子類都可以使用foreach進行迭代
- Iterator中和核心的方法next(),hasnext(),remove(),都是依賴當前位置怔接,如果這些集合直接實現(xiàn)Iterator燥翅,則必須包括當前迭代位置的指針。當集合在方法間進行傳遞的時候蜕提,由于當前位置不可知,所以next()之后的值靶端,也不可知谎势。而當實現(xiàn)Iterable則不然凛膏,每次調(diào)用都返回一個從頭開始的迭代器,各個迭代器之間互不影響脏榆。
-
HashMap的工作原理
- 結(jié)構(gòu):
- HashMap是數(shù)組+鏈表+紅黑樹(JDK1.8增加)實現(xiàn)的猖毫,數(shù)組里存儲的元素是一個Node實體(JDK1.8為Node,之前為Entry)须喂,這個Node實體主要包含hash(定位數(shù)組索引位置)吁断、key、value以及next指針(指向Node)
- JDK1.8當鏈表長度超過8時候引入紅黑樹坞生,增刪改查的特點提高HashMap的性能
- 操作:
- 當
put()
時仔役,根據(jù)鍵值key計算hash值得到數(shù)組索引i,如果數(shù)組值為空則直接新建節(jié)點添加是己,否則判斷table[i]的首個元素是否和key一樣又兵,如果相同直接覆蓋value,哈希碰撞利用鏈表插入卒废,大于8的話把鏈表轉(zhuǎn)換為紅黑樹沛厨,在紅黑樹中執(zhí)行插入操作 - 當
get()
時,獲取指定key的值時摔认,會根據(jù)這個key算出它的hash值(數(shù)組下標)逆皮,根據(jù)這個hash值獲取數(shù)組下標對應的Node,然后判斷Node里的key参袱,hash值或者通過equals()比較是否與要查找的相同电谣,如果相同,返回value蓖柔,否則的話辰企,遍歷該鏈表(有可能就只有一個Node,此時直接返回null)况鸣,長度大于8則變量紅黑樹節(jié)點牢贸,直到找到為止,否則返回null - 擴容機制resize:
- 當
- 哈希碰撞:
- Hash算法本質(zhì)上就是三步:取key的hashCode值镐捧、高位運算(
h ^ (h >>> 16)
)潜索、取模運算 - HashMap使用LinkedList來解決碰撞問題,當發(fā)生碰撞了懂酱,對象將會儲存在LinkedList的下一個節(jié)點中竹习。 HashMap在每個LinkedList節(jié)點中儲存鍵值對對象
- Hash算法本質(zhì)上就是三步:取key的hashCode值镐捧、高位運算(
- 擴容機制:
- DEFAULT_INITIAL_CAPACITY 是初始容量,默認是 1 << 4 = 16
- DEFAULT_LOAD_FACTOR 是負載因子大小為0.75列牺,也就是說整陌,當一個map填滿了75%的bucket時候,擴充2倍,例如泌辫,當前大小是16随夸,當占用超過160.75=12時,就把容量擴充到162=32
- MAXIMUM_CAPACITY是最大容量震放,默認是 2^30
- 當兩個不同的鍵對象的hashcode相同時會發(fā)生什么宾毒?
它們會儲存在同一個bucket位置的LinkedList中。鍵對象的equals()方法用來找到鍵值對殿遂。
- 可以使用CocurrentHashMap來代替HashTable嗎诈铛?
ConcurrentHashMap同步性能更好,因為它僅僅根據(jù)同步級別對map的一部分進行上鎖墨礁。ConcurrentHashMap可以代替HashTable幢竹,但是HashTable提供更強的線程安全性。
- HashMap源碼剖析
- 結(jié)構(gòu):
-
LinkedHashMap的實現(xiàn)原理
- LinkedHashMap也是基于HashMap實現(xiàn)的饵溅,不同的是它定義了一個Entry header妨退,這個header不是放在Table里,它是額外獨立出來的蜕企。LinkedHashMap通過繼承hashMap中的Entry,并添加兩個屬性Entry before,after,和header結(jié)合起來組成一個雙向鏈表咬荷,來實現(xiàn)按插入順序或訪問順序排序。LinkedHashMap定義了排序模式accessOrder轻掩,該屬性為boolean型變量幸乒,對于訪問順序,為true唇牧;對于插入順序罕扎,則為false。一般情況下丐重,不必指定排序模式腔召,其迭代順序即為默認為插入順序
- LinkedHashMap保存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時扮惦,先得到的記錄肯定是先插入的
-
ConcurrentHashMap原理
- ConcurrentHashMap采用 分段鎖的機制臀蛛,實現(xiàn)并發(fā)的更新操作,底層采用數(shù)組+鏈表+紅黑樹的存儲結(jié)構(gòu)崖蜜,其包含兩個核心靜態(tài)內(nèi)部類 Segment和HashEntry
- 默認創(chuàng)建包含16個Segment對象的數(shù)組浊仆,首先將數(shù)據(jù)分成一段一段的存儲(Segment繼承ReentrantLock),每個 Segment 對象守護每個散列映射表的若干個桶(每個桶是由若干個 HashEntry 對象鏈接起來的鏈表)豫领,當一個線程占用鎖訪問其中一個數(shù)據(jù)時抡柿,其它段的數(shù)據(jù)也能被其它的線程訪問修改,而Hashtable鎖的是整個hash表等恐,效率較低
- JDK1.8的實現(xiàn)已經(jīng)拋棄了Segment分段鎖機制洲劣,利用CAS+Synchronized來保證并發(fā)更新的安全备蚓,底層依然采用數(shù)組+鏈表+紅黑樹的存儲結(jié)構(gòu)
- ConcurrentHashMap的size操作
- ConcurrentHashMap源碼分析
-
靜態(tài)方法與單例模式的區(qū)別
- 單例可以繼承類,實現(xiàn)接口闪檬,而靜態(tài)類不能(可以集成類星著,但不能集成實例成員)
- 單例可以被延遲初始化,靜態(tài)類一般在第一次加載是初始化
- 單例類可以被集成粗悯,他的方法可以被覆寫
- 單例類可以被用于多態(tài)而無需強迫用戶只假定唯一的實例
- 靜態(tài)方法中產(chǎn)生的對象,會隨著靜態(tài)方法執(zhí)行完畢而釋放掉同欠,而且執(zhí)行類中的靜態(tài)方法時样傍,不會實例化靜態(tài)方法所在的類。如果是用singleton, 產(chǎn)生的那一個唯一的實例铺遂,會一直在內(nèi)存中衫哥,不會被GC清除的(原因是靜態(tài)的屬性變量不會被GC清除),除非整個JVM退出了
-
普通代碼塊襟锐,構(gòu)造代碼塊撤逢,靜態(tài)代碼塊區(qū)別
- 普通代碼塊:在方法或語句中出現(xiàn)的{}就稱為普通代碼塊。普通代碼塊和一般的語句執(zhí)行順序由他們在代碼中出現(xiàn)的次序決定--“先出現(xiàn)先執(zhí)行”
- 構(gòu)造代碼塊:直接在類中定義且沒有加static關鍵字的代碼塊稱為{}構(gòu)造代碼塊粮坞。構(gòu)造代碼塊在創(chuàng)建對象時被調(diào)用蚊荣,每次創(chuàng)建對象都會被調(diào)用,并且構(gòu)造代碼塊的執(zhí)行次序優(yōu)先于類構(gòu)造函數(shù)
- 靜態(tài)代碼塊:static關鍵字修飾莫杈,用于初始化類互例,為類的屬性初始化。每個靜態(tài)代碼塊只會執(zhí)行一次筝闹。由于JVM在加載類時會執(zhí)行靜態(tài)代碼塊媳叨,所以靜態(tài)代碼塊先于主方法執(zhí)行
- 執(zhí)行順序:靜態(tài)代碼塊>mian方法>構(gòu)造代碼塊>構(gòu)造方法
-
類的初始化順序
- 父類的靜態(tài)變量/靜態(tài)初始化塊;
- 子類類的靜態(tài)變量/靜態(tài)初始化塊;
- 父類的動態(tài)初始化塊(與靜態(tài)初始化塊類似,只是沒有static關鍵字关顷,即放在一對大括號中的代碼塊)糊秆、非構(gòu)造方法和set方法的成員變量初始化;
- 父類的構(gòu)造方法;
- 子類的動態(tài)初始化塊、非構(gòu)造方法和set方法的成員變量初始化;
- 子類的構(gòu)造方法;
- 父類本地變量;
- 子類的本地變量;
-
關于構(gòu)造函數(shù)
- 子類的構(gòu)造方法總是先調(diào)用父類的構(gòu)造方法议双,如果子類的構(gòu)造方法沒有明顯地指明使用父類的哪個構(gòu)造方法痘番,子類就調(diào)用父類不帶參數(shù)的構(gòu)造方法
- 如果父類沒有無參的構(gòu)造函數(shù),子類則需要在自己的構(gòu)造函數(shù)中顯示的調(diào)用父類的構(gòu)造函數(shù)聋伦,super("nm");
-
向上轉(zhuǎn)型和向下轉(zhuǎn)型
- 向上轉(zhuǎn)型:子類引用的對象轉(zhuǎn)換為父類類型稱為向上轉(zhuǎn)型夫偶。通俗地說就是是將子類對象轉(zhuǎn)為父類對象。此處父類對象可以是接口(安全)
- 向下轉(zhuǎn)型:父類引用的對象轉(zhuǎn)換為子類類型稱為向下轉(zhuǎn)型觉增。
- 如果父類引用的對象如果引用的是指向的子類對象兵拢,那么在向下轉(zhuǎn)型的過程中是安全的。也就是編譯是不會出錯誤的逾礁。
- 如果父類引用的對象是父類本身说铃,那么在向下轉(zhuǎn)型的過程中是不安全的访惜,編譯不會出錯,但是運行時會出現(xiàn)java.lang.ClassCastException錯誤腻扇。它可以使用instanceof來避免出錯此類錯誤债热。
-
try-catch-finally執(zhí)行順序
- 不管有木有出現(xiàn)異常,finally塊中代碼都會執(zhí)行幼苛;
- 當try和catch中有return時窒篱,finally仍然會執(zhí)行;
- finally是在return后面的表達式運算后執(zhí)行的(此時并沒有返回運算后的值舶沿,而是先把要返回的值保存起來墙杯,管finally中的代碼怎么樣,返回的值都不會改變括荡,任然是之前保存的值)高镐,所以函數(shù)返回值是在finally執(zhí)行前確定的;
- finally中最好不要包含return畸冲,否則程序會提前退出嫉髓,返回值不是try或catch中保存的返回值。
- 任何執(zhí)行try 或者catch中的return語句之前邑闲,都會先執(zhí)行finally語句算行,如果finally存在的話。
如果finally中有return語句监憎,那么程序就return了纱意,所以finally中的return是一定會被return的 - try中的return語句調(diào)用的函數(shù)先于finally中調(diào)用的函數(shù)執(zhí)行,也就是說return語句先執(zhí)行(但是還沒有返回)鲸阔,finally語句后執(zhí)行
-
JDK新特性
- JDK5.0新特性系列
- JDK7
- Swith判斷可以用String類型
- JDK8
- Lambda表達式偷霉,函數(shù)式接口
- Stream API
-
注解相關
- 理解:
- 元注解:
@Documented @Retention @Target @Inherited
- 標準注解:
@Override @Deprecated @SuppressWarnings
- 元注解:
- 讀取注解信息:
- 獲得注解修飾反射對象 Class Field Method ---- 這些所有反射對象 都實現(xiàn)了 AnnotatedElement接口
- 通過 AnnotatedElement 接口 boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 判斷目標注解是否存在
- 通過 AnnotatedElement 接口
getAnnotation(Class<T> annotationClass)
獲得目標注解
- 理解:
-
泛型相關
- 理解:
- 通配符:
<? super T>
表示包括T在內(nèi)的任何T的父類,<? extends T>
表示包括T在內(nèi)的任何T的子類
- 通配符:
- 優(yōu)點:
- 使用泛型類型可以最大限度地重用代碼褐筛、保護類型的安全以及提高性能
- 泛型最常見的用途是創(chuàng)建集合類
- 缺點:
- 在性能上不如數(shù)組快
- 泛型類:
- 泛型方法:
- 理解:
-
反射相關:
- 理解:
- 反射是一種間接操作目標對象的機制类少,在程序程序運行時獲取或者設置對象自身的信息。 只要給定類的名字渔扎,就可以通過反射獲取類的所有信息硫狞,接著便能調(diào)用它的任何一個方法和屬性。
- 操作步驟:
- 首先反射機制獲取類有三種方法
- Classc1 = Class.forName("Employee");
- Classc2 = Employee.class;
- Classc3 = e.getClass();
- 利用newInstance調(diào)用無參數(shù)構(gòu)造方法
- 獲取屬性晃痴、方法残吩、構(gòu)造方法:有兩種分為所有的和特定的
- 利用setAccessible(true)可以訪問private修飾的屬性或方法
- 首先反射機制獲取類有三種方法
- 應用場景:
- 動態(tài)代理
- 框架:ButterKnife、EventBus倘核、Dagger
- 插件化:調(diào)用系統(tǒng)API泣侮、hook對象
- 優(yōu)化:
- 緩存forName()
- 盡量不要getMethods()后再遍歷篩選,而直接用getMethod(methodName)
- 理解:
-
Java Util Concurrency基礎內(nèi)容概述
- 分類:
- Atomic : AtomicInteger
- Locks : Lock, Condition, ReadWriteLock
- Collections : Queue, ConcurrentMap
- Executer : Future, Callable, Executor
- Tools : CountDownLatch, CyclicBarrier, Semaphore
- 特性:
- 傳統(tǒng)鎖的問題:synchronized關鍵字是基于阻塞的鎖機制紧唱,也就是說當一個線程擁有鎖的時候活尊,訪問同一資源的其它線程需要等待隶校,直到該線程釋放鎖
- Atomic類其內(nèi)部實現(xiàn)不是簡單的使用synchronized,而是一個更為高效的方式CAS (compare and swap) + volatile和native方法蛹锰,從而避免了synchronized的高開銷深胳,執(zhí)行效率大為提升
- 分類:
-
synchronized
- 概述
- synchronized可以保證方法或者代碼塊在運行時,同一時刻只有一個方法可以進入到臨界區(qū)铜犬,同時它還可以保證共享變量的內(nèi)存可見性
- 對象鎖&類鎖
- 對象鎖是用于對象實例方法舞终,或者一個對象實例上的,防止其它線程訪問同一對象中的synchronized代碼塊或者函數(shù)
- 類鎖是用于類的靜態(tài)方法或者一個類的class對象上的癣猾,防止多個線程同時訪問添加了synchronized鎖的代碼塊
- 類的對象實例可以有很多個权埠,但是每個類只有一個class對象,所以不同對象實例的對象鎖是互不干擾的煎谍,但是每個類只有一個類鎖
- 對象鎖是用來控制實例方法之間的同步,類鎖是用來控制靜態(tài)方法(或靜態(tài)變量互斥體)之間的同步
- 實現(xiàn)原理
- 同步代碼塊是使用monitorenter和monitorexit指令實現(xiàn)的龙屉,monitorenter指令插入到同步代碼塊的開始位置呐粘,monitorexit指令插入到同步代碼塊的結(jié)束位置
- synchronized用的鎖是存在Java對象頭里的monitor標記位,monitor被持有之后转捕,他將處于鎖定狀態(tài)作岖,線程執(zhí)行到monitorenter指令時,將會嘗試獲取對象所對應的monitor所有權(quán)五芝,即嘗試獲取對象的鎖
- Java對象頭
- Hotspot虛擬機的對象頭主要包括兩部分數(shù)據(jù):Mark Word(標記字段)痘儡、Klass Pointer(類型指針)
- Klass Point是對象指向它的類元數(shù)據(jù)的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例枢步,Mark Word用于存儲對象自身的運行時數(shù)據(jù)沉删,它是實現(xiàn)輕量級鎖和偏向鎖的關鍵
- Mark Word用于存儲對象自身的運行時數(shù)據(jù),如HashCode醉途、GC分代年齡矾瑰、鎖狀態(tài)標志、線程持有的鎖隘擎、偏向線程 ID殴穴、偏向時間戳等
- 鎖優(yōu)化
- jdk1.6對鎖的實現(xiàn)引入了大量的優(yōu)化,如自旋鎖货葬、適應性自旋鎖采幌、鎖消除、鎖粗化震桶、偏向鎖休傍、輕量級鎖等技術來減少鎖操作的開銷
-
鎖主要存在四中狀態(tài),依次是:無鎖狀態(tài)尼夺、偏向鎖狀態(tài)尊残、輕量級鎖狀態(tài)炒瘸、重量級鎖狀態(tài),他們會隨著競爭的激烈而逐漸升級寝衫。注意鎖可以升級不可降級顷扩,這種策略是為了提高獲得鎖和釋放鎖的效率
- 概述
-
ThreadLocal與Synchronized的使用場景
- ThreadLocal使用場合主要解決多線程中數(shù)據(jù)數(shù)據(jù)因并發(fā)產(chǎn)生不一致問題。ThreadLocal為每個線程的中并發(fā)訪問的數(shù)據(jù)提供一個副本慰毅,通過訪問副本來運行業(yè)務隘截,這樣的結(jié)果是耗費了內(nèi)存,單大大減少了線程同步所帶來性能消耗汹胃,也減少了線程并發(fā)控制的復雜度
- synchronized是利用鎖的機制婶芭,使變量或代碼塊在某一時該只能被一個線程訪問。而ThreadLocal為每一個線程都提供了變量的副本着饥, 使得每個線程在某一時間訪問到的并不是同一個對象犀农,這樣就隔離了多個線程對數(shù)據(jù)的數(shù)據(jù)共享。而Synchronized卻正好相反宰掉,它用于在多個線程間通信時能夠獲得數(shù)據(jù)共享
-
多個線程訪問共享對象和數(shù)據(jù)的方式
- 如果每個線程執(zhí)行的代碼相同呵哨,可以使用同一個Runnable對象,這個Runnable對象中有那個共享數(shù)據(jù)轨奄,例如孟害,買票系統(tǒng)就可以這么做
- 如果每個線程執(zhí)行的代碼不同,這時候需要用不同的Runnable對象挪拟,有如下兩種方式來實現(xiàn)這些Runnable對象之間的數(shù)據(jù)共享
- 將共享數(shù)據(jù)封裝在另外一個對象中挨务,然后將這個對象逐一傳遞給各個Runnable對象。
- 將這些Runnable對象作為某一個類中的內(nèi)部類玉组,共享數(shù)據(jù)作為這個外部類中的成員變量
-
sleep()和wait()區(qū)別
- sleep是Thread類的方法谎柄,wait是Object類的方法。
- sleep是自動喚醒球切,wait需要其他線程來喚醒谷誓。
- sleep不會釋放同步鎖,wait會釋放同步鎖吨凑。
- sleep可以用在任意方法中捍歪,wait只能用在同步方法或同步塊中
- sleep 必須捕獲異常,而 wait,notify 和 notifyAll 不需要捕獲異常
-
Lock
- 簡介
- Lock是一個接口,通過這個接口可以實現(xiàn)同步訪問鸵钝;其中ReentrantLock就是Lock接口的實現(xiàn)類
- Lock的分類
- Lock分為“公平鎖”和“非公平鎖”糙臼,公平鎖就是先等待的線程先獲得鎖
- 實現(xiàn)原理
- ReenTrantLock的實現(xiàn)是一種自旋鎖,通過循環(huán)調(diào)用CAS操作來實現(xiàn)加鎖恩商。它的性能比較好也是因為避免了使線程進入內(nèi)核態(tài)的阻塞狀態(tài)
- 簡介
-
Synchronized 和Lock的用法和區(qū)別
- 區(qū)別:
- Lock是一個接口变逃,而synchronized是Java中的關鍵字,synchronized是內(nèi)置的語言實現(xiàn)
- Lock可以讓等待鎖的線程響應中斷怠堪,而synchronized卻不行揽乱,使用synchronized時名眉,等待的線程會一直等待下去,不能夠響應中斷
- 通過Lock可以知道有沒有成功獲取鎖凰棉,而synchronized卻無法辦到
- 用法:
- Synchronized(隱式鎖)在需要同步的對象损拢、方法加入此控制
- Lock(顯示鎖):需要在指定位置和終止位置上鎖和釋放鎖
- 性能:
- Synchronized是托管給JVM執(zhí)行的(jdk1.6優(yōu)化:自旋鎖、偏向鎖撒犀、輕量鎖福压、重量鎖)
- 而lock是java寫的控制鎖的代碼,Lock還有更強大的功能或舞,例如荆姆,它的tryLock方法可以非阻塞方式去拿鎖
- 機制:
- Lock使用CAS樂觀鎖
- Synchronized使用CPU悲觀鎖
- 區(qū)別:
-
Synchronized和volatile區(qū)別
- volatile僅在變量級別,Synchronized可以在變量映凳、方法胆筒、類
- volatile僅能實現(xiàn)變量的修改可見性,并不能保證原子性诈豌,Synchronized則可以保證可見性和原子性
- volatile不會造成線程的阻塞(沒加鎖)腐泻,Synchronized會造成線程的阻塞
- volatile標記的變量不會被編譯器優(yōu)化,Synchronized標記的變量可以被編譯器優(yōu)化
-
volatile
volatile無法保證原子性队询,計數(shù)時 i++ 這個操作不是原子的
- 作用:
- 保證內(nèi)存可見性
- 禁止指令重排序
- 當程序執(zhí)行到volatile變量的讀操作或者寫操作時,在其前面的操作的更改肯定全部已經(jīng)進行构诚,且結(jié)果已經(jīng)對后面的操作可見蚌斩;在其后面的操作肯定還沒有進行
- 在進行指令優(yōu)化時,不能將在對volatile變量訪問的語句放在其后面執(zhí)行范嘱,也不能把volatile變量后面的語句放到其前面執(zhí)行
- 使用場景:
- 狀態(tài)標記量
- double check
- volatile的原理和實現(xiàn)機制:
- 加入volatile關鍵字時送膳,會多出一個lock前綴指令,lock前綴指令實際上相當于一個內(nèi)存屏障
- 作用:
-
內(nèi)存屏障
- 它確保指令重排序時不會把其后面的指令排到內(nèi)存屏障之前的位置丑蛤,也不會把前面的指令排到內(nèi)存屏障的后面叠聋;即在執(zhí)行到內(nèi)存屏障這句指令時,在它前面的操作已經(jīng)全部完成
- 它會強制將對緩存的修改操作立即寫入主存
- 如果是寫操作受裹,它會導致其他CPU中對應的緩存行無效
-
原子性碌补、可見性
- 可見性:是指線程之間的可見性,一個線程的修改的狀態(tài)對另一個線程是可見的棉饶,也就是一個線程的修改的結(jié)果厦章,另一線程馬上能看見
- 原子性:操作不可以中途被cpu暫停然后調(diào)度,即不能中斷照藻,要不執(zhí)行完袜啃,要不就不執(zhí)行
-
線程、進程區(qū)別
- 一個進程內(nèi)部可以有多個線程
- 進程擁有獨立的地址空間幸缕,同一進程下的線程可以共享改內(nèi)存區(qū)域群发,線程有自己的堆棧和局部變量晰韵,但是線程沒有獨立的地址空間
- 進程是資源分配的基本單位,線程是CPU調(diào)度的基本單位
- 調(diào)度和切換:線程上下文切換比進程上下文切換要快得多熟妓,線程開銷相對較小
-
鎖的分類以及辨析
- 公平鎖/非公平鎖:公平鎖是指多個線程按照申請鎖的順序來獲取鎖雪猪,非公平鎖是指多個線程獲取鎖的順序并不是按照申請鎖的順序,對于Java ReentrantLock而言滑蚯,通過構(gòu)造函數(shù)指定該鎖是否是公平鎖浪蹂,默認是非公平鎖。
- 可重入鎖:可重入鎖又名遞歸鎖告材,是指在同一個線程在外層方法獲取鎖的時候话侄,在進入內(nèi)層方法會自動獲取鎖(ReentrantLock、synchronized)
- 獨享鎖/共享鎖:獨享鎖是指該鎖一次只能被一個線程所持有(Java ReentrantLock)艾君,但是對于Lock的另一個實現(xiàn)類ReadWriteLock氛琢,其讀鎖是共享鎖,其寫鎖是獨享鎖
- 互斥鎖/讀寫鎖:一般的synchronized疤剑、ReentrantLock就是互斥鎖滑绒,ReadWriteLock是讀寫鎖
- 樂觀鎖/悲觀鎖:不是指具體的什么類型的鎖,而是指看待并發(fā)同步的角度隘膘,樂觀鎖(CAS)疑故,悲觀就是利用各種鎖
- 自旋鎖/阻塞鎖: 自旋鎖是指嘗試獲取鎖的線程不會立即阻塞,而是采用循環(huán)的方式去嘗試獲取鎖弯菊,這樣的好處是減少線程上下文切換的消耗纵势,缺點是循環(huán)會消耗CPU(CAS原子操作實現(xiàn))
- 偏向鎖/輕量級鎖/重量級鎖:這三種鎖是指鎖的狀態(tài),并且是針對Synchronized進行優(yōu)化的
-
線程池相關
- 優(yōu)點:
- 減少在創(chuàng)建和銷毀線程上所花的時間以及系統(tǒng)資源的開銷
- 避免大量的線程間因互相搶占系統(tǒng)資源導致的阻塞現(xiàn)象
- 能夠?qū)€程進行簡單的管理并提供定時執(zhí)行管钳、間隔執(zhí)行等功能
- 基本組成部分:
- 線程池管理器(ThreadPool):用于創(chuàng)建并管理線程池钦铁,包括 創(chuàng)建線程池,銷毀線程池才漆,添加新任務牛曹;
- 工作線程(PoolWorker):線程池中線程,在沒有任務時處于等待狀態(tài)醇滥,可以循環(huán)的執(zhí)行任務黎比;
- 任務接口(Task):每個任務必須實現(xiàn)的接口,以供工作線程調(diào)度任務的執(zhí)行鸳玩,它主要規(guī)定了任務的入口焰手,任務執(zhí)行完后的收尾工作,任務的執(zhí)行狀態(tài)等怀喉;
- 任務隊列(taskQueue):用于存放沒有處理的任務书妻。提供一種緩沖機制。
- 優(yōu)點:
-
finalize() 和 system.gc() 的區(qū)別
- gc 只能清除在堆上分配的內(nèi)存(純java語言的所有對象都在堆上使用new分配內(nèi)存),而不能清除棧上分配的內(nèi)存(當使用JNI技術時,可能會在棧上分配內(nèi)存,例如java調(diào)用c程序,而該c程序使用malloc分配內(nèi)存時).因此,如果某些對象被分配了棧上的內(nèi)存區(qū)域,那gc就管不著了,對這樣的對象進行內(nèi)存回收就要靠finalize()
- finalize的工作原理應該是這樣的:一旦垃圾收集器準備好釋放對象占用的存儲空間躲履,它首先調(diào)用finalize()见间,而且只有在下一次垃圾收集過程中,才會真正回收對象的內(nèi)存.所以如果使用finalize()工猜,就可以在垃圾收集期間進行一些重要的清除或清掃工作.
- finalize()在什么時候被調(diào)用?
- 所有對象被Garbage Collection時自動調(diào)用,比如運行System.gc()的時候
- 程序退出時為每個對象調(diào)用一次finalize方法
- 顯式的調(diào)用finalize方法
- Java程序在調(diào)用C++時需要調(diào)用finalize()方法來釋放內(nèi)存
-
終止線程的方法
- 使用退出標志Flag米诉,使線程正常退出,也就是當run方法完成后線程終止
- 使用stop方法強行終止線程(這個方法不推薦使用篷帅,因為stop和suspend史侣、resume一樣,也可能發(fā)生不可預料的結(jié)果)魏身。
- 使用interrupt方法中斷線程
-
IoC思想
- IOC的核心是解耦惊橱,解耦的目的是修改耦合對象時不影響另外一個對象…降低模塊之間的關聯(lián)
- 在Android中主要是減少 findviewById(R.id.text)、setXXXListener的操作
- Android提過的框架有Dagger2和butterKnife箭昵,底層原理是注解税朴、反射
-
AOP思想
- 面向切面編程,需要把程序邏輯分解成『關注點』(concerns家制,功能的內(nèi)聚區(qū)域)正林。這意味著,在 AOP 中颤殴,我們不需要顯式的修改就可以向代碼中添加可執(zhí)行的代碼塊觅廓。這種編程范式假定『橫切關注點』,多處代碼中需要的邏輯涵但,但沒有一個單獨的類來實現(xiàn))應該只被實現(xiàn)一次哪亿,且能夠多次注入到需要該邏輯的地方
- 應用場景:日志、持久化贤笆、性能監(jiān)控
- Android中框架:AspectJ、Dexposed