JVM
JVM是運行Java字節(jié)碼的虛擬機(jī)搀继。JVM有針對不同系統(tǒng)的特定實現(xiàn)叽躯,目的在不同的系統(tǒng)平臺上運行相同的字節(jié)碼啡专。.java文件經(jīng)過JDK的javac編譯為.class文件们童,.class文件又被JVM編譯成機(jī)器可執(zhí)行的二進(jìn)制機(jī)器碼慧库。
我們需要格外注意的是 .class->機(jī)器碼 這一步齐板。在這一步 jvm 類加載器首先加載字節(jié)碼文件甘磨,然后通過解釋器逐行
解釋執(zhí)行,這種方式的執(zhí)行速度會相對比較慢卿泽。而且签夭,有些方法和代碼塊是經(jīng)常需要被調(diào)用的椎侠,也就是所謂的熱點代碼我纪,所以后面引進(jìn)了 JIT 編譯器璧诵,JIT 屬于運行時編譯仇冯。當(dāng) JIT 編譯器完成第一次編譯后比被,其會將字節(jié)碼對應(yīng)的機(jī)器碼保存下來等缀,下次可以直接使用尺迂。而我們知道噪裕,機(jī)器碼的運行效率肯定是高于 Java 解釋器的膳音。這也解釋了我們 為什么經(jīng)常會說 Java 是編譯與解釋共存的語言祭陷。
HotSpot采用了惰性評估(Lazy Evaluation)的做法兵志,根據(jù)二八定律,消耗大部分系統(tǒng)資源的只有那一小部分的代碼(熱點代碼)哑蔫,而這也就是JIT所需要編譯的部分闸迷。JVM會根據(jù)代碼每次被執(zhí)行的情況收集信息并相應(yīng)地做出一些優(yōu)化俘枫,因此執(zhí)行的次數(shù)越多,它的速度就越快今阳。JDK 9引入了一種新的編譯模式AOT(Ahead of Time Compilation)盾舌,它是直接將字節(jié)碼編譯成機(jī)器碼,這樣就避免了JIT預(yù)熱等各方面的開銷蘸鲸。JDK支持分層編譯和AOT協(xié)作使用妖谴。但是 ,AOT 編譯器的編譯質(zhì)量是肯定比不上 JIT 編譯器的酌摇。
重載與重寫
重載:發(fā)生在同一類中膝舅,方法名相同,方法簽名(參數(shù)類型窑多、個數(shù)仍稀、順序不同)可能不同;注意埂息,返回類型和訪問修飾符不算在方法簽名中技潘,不能作為重載的判斷依據(jù)。
重寫:發(fā)生在繼承類中千康,方法簽名需要相同琉闪,方訪問權(quán)限子類中實現(xiàn)需要大于等于父類中實現(xiàn)砂碉。
構(gòu)造器Constructor是否可以被override滴某?
父類的構(gòu)造方法和私有屬性不能被繼承幕侠,所以Constructor也不能被重寫(override)庇忌,但是可以被重載(overload)。
Java面向?qū)ο缶幊倘筇匦?/h4>
封裝、繼承立砸、多態(tài)螺戳,其中多態(tài)指定是程序的引用變量可以在運行時的向上轉(zhuǎn)型動態(tài)確定损同。Java中可以通過繼承和接口實現(xiàn)多態(tài)。
String、StringBuilder蛛砰、StringBuffer
可變性:首先String是用final修飾的保存字符的數(shù)組们豌,因為字符串是不可變的,所以當(dāng)直接定義字符串(如:"abc")時,會去常量池中尋找該變量值,存在直接返回使用迟隅,不存在再行創(chuàng)建;StringBuilder和StringBuffer都是繼承自AbstractStringBuilder類瞳步,該類也是使用數(shù)組保存字符串馏臭,和String不同的是沒有使用final修飾,所以是可變的。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
...
}
線程安全性:String是不可變的,所以線程安全盗誊;StringBuffer是線程安全的开镣;StringBuilder是非線程安全的卧蜓,所以性能比StringBuffer高一點盛霎。
==和equals()
默認(rèn)情況下==用來比較兩個對象的引用地址是否相同规个,或者比較兩個常量(基礎(chǔ)類型分布在常量池中)是否相等墅拭;equals用來比較對象的具體屬性的值是否相等谍婉;有時我們只需要比較兩個對象包含的屬性值是否相等镀迂,這時可以重寫equals方法來實現(xiàn)招拙。
Object的hashCode()和HashMap中的hashCode()
在使用==判斷兩個變量是否相等规哪,比較的是兩個變量的內(nèi)存地址杯巨,和Object的hashCode()并沒有直接的關(guān)系逗爹;先看Object中的hashCode():
/**
* Returns a hash code value for the object. This method is
* supported for the benefit of hash tables such as those provided by
* {@link java.util.HashMap}.
* <p>
* The general contract of {@code hashCode} is:
* <ul>
* <li>Whenever it is invoked on the same object more than once during
* an execution of a Java application, the {@code hashCode} method
* must consistently return the same integer, provided no information
* used in {@code equals} comparisons on the object is modified.
* This integer need not remain consistent from one execution of an
* application to another execution of the same application.
* <li>If two objects are equal according to the {@code equals(Object)}
* method, then calling the {@code hashCode} method on each of
* the two objects must produce the same integer result.
* <li>It is <em>not</em> required that if two objects are unequal
* according to the {@link java.lang.Object#equals(java.lang.Object)}
* method, then calling the {@code hashCode} method on each of the
* two objects must produce distinct integer results. However, the
* programmer should be aware that producing distinct integer results
* for unequal objects may improve the performance of hash tables.
* </ul>
* <p>
* As much as is reasonably practical, the hashCode method defined by
* class {@code Object} does return distinct integers for distinct
* objects. (This is typically implemented by converting the internal
* address of the object into an integer, but this implementation
* technique is not required by the
* Java™ programming language.)
*
* @return a hash code value for this object.
* @see java.lang.Object#equals(java.lang.Object)
* @see java.lang.System#identityHashCode
*/
public native int hashCode();
首先看到這是一個native方法持舆,方法注釋
- This method is supported for the benefit of hash tables such as those provided by {@link java.util.HashMap}色瘩,所以這是為什么比較兩個對象是否相等(值相等使用equals,內(nèi)存地址相等使用==)沒有用到hashCode方法逸寓,卻非要在Object類中添加對hashCode的支持的原因居兆;
- 在同一對象上調(diào)用多次hashCode()應(yīng)該始終返回相同的int值;
- 如果ObjA.equals(ObjB)竹伸,那么ObjA的hashCode一定等于ObjB泥栖;
- 兩個對象相互equals,不代表他們的hashCode一定不相等(即所謂的哈希碰撞)勋篓。
其次HashMap只是一種數(shù)據(jù)結(jié)構(gòu)吧享,其存在的理由是為了集成類似數(shù)組的快速查找,又想避免為了存儲少數(shù)大范圍值的數(shù)據(jù)而創(chuàng)建一個大數(shù)組的問題譬嚣。通過hash函數(shù)可以把這些大范圍值的數(shù)據(jù)映射到HashMap的數(shù)組中去钢颂,如果發(fā)生哈希碰撞,則會是使用鏈表拜银,而在Java 8.0以后殊鞭,使用紅黑樹替代了鏈表;
具體HashMap可參考:HashMap實現(xiàn)原理及源碼分析
equals()和hashCode()
? 以HashSet為例尼桶,當(dāng)需要插入操灿、查詢一個對象時,先計算該對象的hashCode,看是否存在相同的hashCode泵督,如果存在趾盐,再對比他們的equals方法是否相等,如果equals方法也相等,則表明是同一個對象谤碳,拒絕插入溃卡;如果equals方法不相等,則對對象的重新進(jìn)行hash蜒简,插入到其他位置瘸羡。
Java中的序列化和反序列化(Serializable)
? Java序列化就是將一個對象轉(zhuǎn)化為一個****二進(jìn)制表示的字節(jié)數(shù)組
,如果不想對某些字段進(jìn)行序列化搓茬,可以使用transient關(guān)鍵字修飾犹赖;在反序列化時如果serialVersionUID被修改的話,反序列化會失斁砺亍峻村;當(dāng)父類實現(xiàn)了Serializable接口的時候,所有的子類都能被序列化锡凝,當(dāng)子類實現(xiàn)Serializable接口時粘昨,父類沒有,則父類中的屬性不能被序列化窜锯。
Collections類和Arrays工具類的常用方法
Collections類
- 排序:sort(List)张肾、sort(List, Comparator)、swap(list, i , j)
- 查找:binarySearch(list , key)锚扎、max(Collection)吞瞪、indexOfSubList(List list, List target)
- 替換:replaceAll(List list, Object oldVal, Object newVal)
Arrays類
- 排序:sort(List)
val iArray = intArrayOf(1, 3, 4, 5, 6, 7, 8, 8, 6, 5, 4)
Arrays.sort(iArray)
for (v in iArray) {
print("$v ")
}
>>>輸出:1 3 4 4 5 5 6 6 7 8 8
- 比較:equals()
val arrayA = intArrayOf(1,3,5)
val arrayB = intArrayOf(1,3,5)
println(Arrays.equals(arrayA,arrayB))
>>>輸出:true
- 轉(zhuǎn)列表:asList()
val names = Arrays.asList("Larry", "Moe", "Curly")
println(names)
>>>輸出:[Larry, Moe, Curly]
Java基礎(chǔ)關(guān)鍵字
final
- 當(dāng)final用來修飾變量時,如果變量是基本數(shù)據(jù)類型驾孔,則其數(shù)值不能改變芍秆;如果變量時引用類型,則改變量不能在再指向另一個對象翠勉。
- 當(dāng)一個方法被final修飾時妖啥,表示該方法不能被繼承類重寫。
- 當(dāng)一個類使用final修飾時眉菱,該類不能被繼承迹栓,該類中所有方法都會隱式的被定義為final方法。
static
- 被static修飾的成員屬于類俭缓,被類中所有對象共享克伊,靜態(tài)變量被分配在方法區(qū),被所有線程共享华坦。
-
靜態(tài)代碼塊愿吹,靜態(tài)代碼在非靜態(tài)代碼執(zhí)行之前執(zhí)行,且
不管改類創(chuàng)建多少對象惜姐,靜態(tài)代碼只執(zhí)行一次
犁跪。 -
靜態(tài)內(nèi)部類椿息,和非靜態(tài)內(nèi)部類最大的區(qū)別在于,
非靜態(tài)內(nèi)部類在編譯后會隱含地保存著一個指向創(chuàng)建他的外部類的引用坷衍,而靜態(tài)內(nèi)部類沒有這個引用
寝优。經(jīng)常這里會問到內(nèi)存泄露的問題。
為什么static方法中不能使用this和super枫耳?
static修飾靜態(tài)方法是屬于類的乏矾;而this指向當(dāng)前對象,super代表父類對象引用迁杨;靜態(tài)方法屬于類钻心,而this、super針對對象铅协。同樣的問題還有:為什么不能在靜態(tài)方法內(nèi)調(diào)用外部類的非靜態(tài)成員捷沸?一樣的答案。