試了好多博客平臺(tái)杉武,最后決定留在掘金啦艺智。準(zhǔn)備好好整理一下java的一些面試經(jīng)典問題圾亏,文章部分來(lái)源網(wǎng)上加入一些自己的見解十拣,PS: 別小看基礎(chǔ)題
1.關(guān)于 JVM JDK 和 JRE
JVM
Java虛擬機(jī)(JVM)是運(yùn)行Java字節(jié)碼的虛擬機(jī)。JVM有針對(duì)不同系統(tǒng)的特定實(shí)現(xiàn)志鹃,目的是使用相同的字節(jié)碼夭问,它們都會(huì)給出相同的結(jié)果。
JVM可以理解的代碼就叫做字節(jié)碼(即擴(kuò)展名為 .class 的文件)
Java 程序從源代碼到運(yùn)行一般有下面3步:
java程序運(yùn)行過程
我們需要格外注意的是 .class->機(jī)器碼這一步曹铃。在這一步JVM類加載器首先加載字節(jié)碼文件缰趋,然后通過解釋器逐行解釋執(zhí)行,這種方式的執(zhí)行速度會(huì)相對(duì)比較慢陕见。而且秘血,有些方法和代碼塊是經(jīng)常需要被調(diào)用的(也就是所謂的熱點(diǎn)代碼),所以后面引進(jìn)了JIT編譯器评甜,而JIT屬于運(yùn)行時(shí)編譯灰粮。當(dāng)JIT編譯器完成第一次編譯后,其會(huì)將字節(jié)碼對(duì)應(yīng)的機(jī)器碼保存下來(lái)忍坷,熱點(diǎn)代碼則下次可以直接使用而不用再次解釋粘舟。而我們知道,機(jī)器碼的運(yùn)行效率肯定是高Java解釋器的佩研。這也解釋了我們?yōu)槭裁唇?jīng)常會(huì)說(shuō)Java是編譯與解釋共存的語(yǔ)言柑肴。
HotSpot采用了惰性評(píng)估法,根據(jù)二八定律旬薯,消耗大部分系統(tǒng)資源的只有那一小部分的代碼(熱點(diǎn)代碼)晰骑,而這也就是JIT所需要編譯的部分。JVM會(huì)根據(jù)代碼每次被執(zhí)行的情況收集信息并相應(yīng)地做出一些優(yōu)化绊序,因此執(zhí)行的次數(shù)越多些侍,它的速度就越快。JDK 9引入了一種新的編譯模式AOT(Ahead ofTimeCompilation)政模,它是直接將字節(jié)碼編譯成機(jī)器碼,這樣就避免了JIT預(yù)熱等各方面的開銷蚂会。JDK支持分層編譯和AOT協(xié)作使用淋样。但是 ,AOT 編譯器的編譯質(zhì)量是肯定比不上 JIT 編譯器的胁住。
字節(jié)碼和不同系統(tǒng)的 JVM 實(shí)現(xiàn)是 Java 語(yǔ)言“一次編譯趁猴,隨處可以運(yùn)行”的關(guān)鍵所在刊咳。
JDK和JRE
JDK是Java Development Kit,它是功能齊全的Java SDK儡司。它擁有JRE所擁有的一切娱挨,還有編譯器(javac)和工具(如javadoc和jdb)。它能夠創(chuàng)建和編譯程序捕犬。
JRE 是 Java運(yùn)行時(shí)環(huán)境跷坝。它是運(yùn)行已編譯 Java 程序所需的所有內(nèi)容的集合,包括 Java虛擬機(jī)(JVM)碉碉,Java類庫(kù)柴钻,java命令和其他的一些基礎(chǔ)構(gòu)件。但是垢粮,它不能用于程序開發(fā)贴届。
2.基礎(chǔ)到枯的面試題-見一個(gè)加一個(gè)
- Java 面向?qū)ο缶幊倘筇匦? 封裝(private...) 繼承(extends) 多態(tài)(implements)
- 構(gòu)造器 (Constructor) 不能 重寫(override) 但是可以重載。
- 抽象類和類都可以實(shí)現(xiàn)多個(gè)接口蜡吧,但是抽象類可以不實(shí)現(xiàn)或選擇性實(shí)現(xiàn)接口方法毫蚓。
- 接口可以被接口(interface)繼承(extends)。
-
字符常量
相當(dāng)于一個(gè)整型值( ASCII 值),可以參加表達(dá)式運(yùn)算 eg: 'C';字符串常量
代表一個(gè)地址值(該字符串在內(nèi)存中存放位置) eg: "C" - 靜態(tài)方法里面不能調(diào)用非靜態(tài)變量昔善,不能訪問非靜態(tài)成員變量元潘。
- 如果有二貨問你java和javax有什么區(qū)別,emm就說(shuō)是歷史遺留名字而已其實(shí)沒什么區(qū)別耀鸦。
- 接口在Java8 以后方法可以有默認(rèn)方法和靜態(tài)方法了柬批,接口中的成員變量必須是public static final的
- 抽象類中的抽象方法(其前有abstract修飾)不能用private、static袖订、protected氮帐、final、synchronized洛姑、native訪問修飾符修飾上沐。
- 外部接口和類不能被private和protected修飾,但是內(nèi)部接口和內(nèi)部類可以被四種訪問修飾符修飾楞艾。
- 如果同時(shí)實(shí)現(xiàn)兩個(gè)接口参咙,接口中定義了一樣的默認(rèn)方法,必須重寫硫眯,不然會(huì)報(bào)錯(cuò)
- 成員變量可以被 public,private,static 等修飾符所修飾蕴侧,而局部變量不能被訪問控制修飾符及 static 所修飾;但是两入,成員變量和局部變量都能被 final 所修飾
3.String StringBuild StringBuffer 用法和區(qū)別
String是不可變的净宵,值由final修飾,StringBuild和StringBuffer都繼承自AbstractStringBuilder。值可變择葡。這也導(dǎo)致了每次對(duì)String類型進(jìn)行改變時(shí)都會(huì)生成一個(gè)新的String對(duì)象紧武,改變內(nèi)存地址指向新的對(duì)象。而StringBuffer每次都會(huì)對(duì)StringBuffer 對(duì)象本身進(jìn)行操作敏储,而不是生成新的對(duì)象并改變對(duì)象引用阻星,StringBuilder 與StringBuffer對(duì)象不同的地方是,StringBuilder對(duì)象沒有同步鎖已添,性能更高但同時(shí)也是線程不安全的妥箕。
使用總結(jié):
1.操作少量的數(shù)據(jù): 適用String(少量數(shù)據(jù)時(shí)更方便)
2.單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù): 適用StringBuilder(線程不安全)
3.多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù): 適用StringBuffer(有同步鎖線程安全)
4.空構(gòu)造器的作用
Java 程序在執(zhí)行子類的構(gòu)造方法之前,如果沒有用 super() 來(lái)調(diào)用父類特定的構(gòu)造方法酝碳,則會(huì)調(diào)用父類中“沒有參數(shù)的構(gòu)造方法”矾踱。因此,如果父類中只定義了有參數(shù)的構(gòu)造方法疏哗,而在子類的構(gòu)造方法中又沒有用 super() 來(lái)調(diào)用父類中特定的構(gòu)造方法呛讲,則編譯時(shí)將發(fā)生錯(cuò)誤,因?yàn)?Java 程序在父類中找不到?jīng)]有參數(shù)的構(gòu)造方法可供執(zhí)行返奉。解決辦法是在父類里加上一個(gè)不做事且沒有參數(shù)的構(gòu)造方法贝搁。
也就是說(shuō)很有可能被繼承的類都需要一個(gè)空構(gòu)造方法。
5.== 與 equals
== : 它的作用是判斷兩個(gè)對(duì)象的地址是不是相等芽偏。即雷逆,判斷兩個(gè)對(duì)象是不是同一個(gè)對(duì)象(基本數(shù)據(jù)類型==比較的是值,引用數(shù)據(jù)類型==比較的是內(nèi)存地址)污尉。
equals() : 它的作用也是判斷兩個(gè)對(duì)象是否相等膀哲。但它一般有兩種使用情況:
- 情況1:類沒有覆蓋 equals() 方法。則通過 equals() 比較該類的兩個(gè)對(duì)象時(shí)被碗,等價(jià)于通過“==”比較這兩個(gè)對(duì)象某宪。
- 情況2:類覆蓋了 equals() 方法。一般锐朴,我們都覆蓋 equals() 方法來(lái)比較兩個(gè)對(duì)象的內(nèi)容是否相等兴喂;若它們的內(nèi)容相等,則返回 true (即焚志,認(rèn)為這兩個(gè)對(duì)象相等)衣迷。
舉個(gè)例子:
public class test1 {
public static void main(String[] args) {
String a = new String("ab"); // a 為一個(gè)引用
String b = new String("ab"); // b為另一個(gè)引用,對(duì)象的內(nèi)容一樣
String aa = "ab"; // 放在常量池中
String bb = "ab"; // 從常量池中查找
if (aa == bb) // true
System.out.println("aa==bb");
if (a == b) // false,非同一對(duì)象
System.out.println("a==b");
if (a.equals(b)) // true
System.out.println("aEQb");
if (42 == 42.0) { // true
System.out.println("true");
}
}
}
說(shuō)明:
String 中的 equals 方法是被重寫過的酱酬,因?yàn)?object 的 equals 方法是比較的對(duì)象的內(nèi)存地址壶谒,而 String 的 equals 方法比較的是對(duì)象的值。
當(dāng)創(chuàng)建 String 類型的對(duì)象時(shí)膳沽,虛擬機(jī)會(huì)在常量池中查找有沒有已經(jīng)存在的值和要?jiǎng)?chuàng)建的值相同的對(duì)象佃迄,如果有就把它賦給當(dāng)前引用泼差。如果沒有就在常量池中重新創(chuàng)建一個(gè) String 對(duì)象。