2020-10-15

1.面向?qū)ο蠛兔嫦蜻^(guò)程的區(qū)別

面向過(guò)程

優(yōu)點(diǎn):性能比面向?qū)ο蟾?,因?yàn)轭愓{(diào)用時(shí)需要實(shí)例化,開銷比較大,比較消耗資源。比如單片機(jī)、嵌入式開發(fā)、Linux/Unix,等一般采用面向過(guò)程開發(fā),性能是最重要的因素。

缺點(diǎn):沒有面向?qū)ο笠拙S護(hù)、易復(fù)用、易擴(kuò)展

面向?qū)ο?/p>

優(yōu)點(diǎn):易維護(hù)、易復(fù)用、易擴(kuò)展,由于面向?qū)ο笥蟹庋b、繼承、多態(tài)性的特性,可以設(shè)計(jì)出低耦合的系統(tǒng),使系統(tǒng)更加靈活、更加易于維護(hù)

缺點(diǎn):性能比面向過(guò)程低

2.Java語(yǔ)言有哪些特點(diǎn)

1.簡(jiǎn)單易學(xué);

2.面向?qū)ο螅ǚ庋b,繼承,多態(tài));

3.平臺(tái)無(wú)關(guān)性(Java虛擬機(jī)實(shí)現(xiàn)平臺(tái)無(wú)關(guān)性);

4.可靠性;

5.安全性;

6.支持多線程(C++語(yǔ)言沒有內(nèi)置的多線程機(jī)制,因此必須調(diào)用操作系統(tǒng)的多線程功能來(lái)進(jìn)行多線程程序設(shè)計(jì),而Java語(yǔ)言卻提供了多線程支持);

7.支持網(wǎng)絡(luò)編程并且很方便(Java語(yǔ)言誕生本身就是為簡(jiǎn)化網(wǎng)絡(luò)編程設(shè)計(jì)的,因此Java語(yǔ)言不僅支持網(wǎng)絡(luò)編程而且很方便);

8.編譯與解釋并存;

3.關(guān)于JVMJDK和JRE最詳細(xì)通俗的解答

JVM

Java虛擬機(jī)(JVM)是運(yùn)行Java字節(jié)碼的虛擬機(jī)。JVM有針對(duì)不同系統(tǒng)的特定實(shí)現(xiàn)(Windows,Linux,macOS),目的是使用相同的字節(jié)碼,它們都會(huì)給出相同的結(jié)果。

什么是字節(jié)碼?采用字節(jié)碼的好處是什么?

在Java中,JVM可以理解的代碼就叫做字節(jié)碼(即擴(kuò)展名為.class的文件),它不面向任何特定的處理器,只面向虛擬機(jī)。Java

語(yǔ)言通過(guò)字節(jié)碼的方式,在一定程度上解決了傳統(tǒng)解釋型語(yǔ)言執(zhí)行效率低的問(wèn)題,同時(shí)又保留了解釋型語(yǔ)言可移植的特點(diǎn)。所以Java程序運(yùn)行時(shí)比較高效,而且,由于字節(jié)碼并不專對(duì)一種特定的機(jī)器,因此,Java程序無(wú)須重新編譯便可在多種不同的計(jì)算機(jī)上運(yùn)行。

Java程序從源代碼到運(yùn)行一般有下面3步:

我們需要格外注意的是.class->機(jī)器碼這一步。在這一步j(luò)vm類加載器首先加載字節(jié)碼文件,然后通過(guò)解釋器逐行解釋執(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),下次可以直接使用。而我們知道,機(jī)器碼的運(yùn)行效率肯定是高于Java解釋器的。這也解釋了我們?yōu)槭裁唇?jīng)常會(huì)說(shuō)Java是編譯與解釋共存的語(yǔ)言。

HotSpot采用了惰性評(píng)估(LazyEvaluation)的做法,根據(jù)二八定律,消耗大部分

系統(tǒng)資源的只有那一小部分的代碼(熱點(diǎn)代碼),而這也就是JIT所需要編譯

的部分。JVM會(huì)根據(jù)代碼每次被執(zhí)行的情況收集信息并相應(yīng)地做出一些優(yōu)化,因此執(zhí)行的次數(shù)越多,它的速度就越快。JDK9

引入了一種新的編譯模式AOT(Ahead of Time Compilation),它是直接將字節(jié)碼編譯成機(jī)器碼,這樣就避免了

JIT預(yù)熱等各方面的開銷。JDK支持分層編譯和AOT協(xié)作使用。但是,AOT編譯器的編譯質(zhì)量是肯定比不上JIT

編譯器的。

總結(jié):Java虛擬機(jī)(JVM)是運(yùn)行Java字節(jié)碼的虛擬機(jī)。JVM有針對(duì)不同系統(tǒng)的特定實(shí)現(xiàn)(Windows,Linux,macOS),的是使用相同的字節(jié)碼,它們都會(huì)給出相同的結(jié)果。字節(jié)碼和不同系統(tǒng)的JVM實(shí)現(xiàn)是Java語(yǔ)言“一次編譯,隨處可以運(yùn)行”的關(guān)鍵所在。

JDK和JRE

JDK是JavaDevelopmentKit,它是功能齊全的JavaSDK。它擁有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)件。但是,它不能用于創(chuàng)建新程序。如果你只是為了運(yùn)行一下Java

程序的話,那么你只需要安裝JRE就可以了。如果你需要進(jìn)行一些Java編程方面的工作,那么你就需要安裝JDK

了。但是,這不是絕對(duì)的。有時(shí),即使您不打算在計(jì)算機(jī)上進(jìn)行任何Java開發(fā),仍然

需要安裝JDK。例如,如果要使用JSP部署Web應(yīng)用程序,那么從技術(shù)上講,您只是在應(yīng)用程序服務(wù)器中運(yùn)行Java程序。那為什么需要JDK呢?因?yàn)閼?yīng)用程序服務(wù)器會(huì)將JSP轉(zhuǎn)換為Javaservlet,并且需要使用JDK來(lái)編譯servlet.

4.OracleJDK和OpenJDK的對(duì)比

可能在看這個(gè)問(wèn)題之前很多人和我一樣并沒有接觸和使用過(guò)OpenJDK。那么Oracle和OpenJDK之間是否存在重大差異?下面通過(guò)我通過(guò)我收集到一些資料對(duì)你解答這個(gè)被很多人忽視的問(wèn)題。對(duì)于Java7,沒什么關(guān)鍵的地方。OpenJDK項(xiàng)目主要基于Sun捐贈(zèng)的HotSpot源代碼。此外,OpenJDK被選為Java7的參考實(shí)現(xiàn),由Oracle工程師維護(hù)。關(guān)于JVM,JDK,JRE和OpenJDK之間的區(qū)別,Oracle博客帖子在2012年有一個(gè)更詳細(xì)的答案:

問(wèn):OpenJDK存儲(chǔ)庫(kù)中的源代碼與用于構(gòu)建OracleJDK的代碼之間什么區(qū)別?

答:非常接近-我們的OracleJDK版本構(gòu)建過(guò)程基于OpenJDK7構(gòu)建,只添加了幾個(gè)部分,例如部署代碼,其中包括Oracle的Java插件和JavaWebStart的實(shí)現(xiàn),以及一些封閉的源代碼派對(duì)組件,如圖形光柵化器,一些開源的第三方組件,如

Rhino,以及一些零碎的東西,如附加文檔或第三方字體。展望未來(lái),我們的目的是開源OracleJDK的所有部分,除了我們考慮商業(yè)功能的部分。

總結(jié):

1.OracleJDK版本將每三年發(fā)布一次,而OpenJDK版本每三個(gè)月發(fā)布一次;

2.OpenJDK是一個(gè)參考模型并且是完全開源的,而OracleJDK是OpenJDK的一個(gè)實(shí)現(xiàn),并不是完全開源的;

3.OracleJDK比OpenJDK更穩(wěn)定。OpenJDK和OracleJDK的代碼幾乎相同,但OracleJDK有更多的類和一些錯(cuò)誤修復(fù)。因此,如果您想開發(fā)企業(yè)/商業(yè)軟件,我建議您選擇OracleJDK,因?yàn)樗?jīng)過(guò)了徹底的測(cè)試和穩(wěn)定。某些情況下,有些人提到在使用OpenJDK可能會(huì)遇到了許多應(yīng)用程序崩潰的問(wèn)題,但是,只需切換到OracleJDK就可以解決問(wèn)題;

4.頂級(jí)公司正在使用OracleJDK,例如AndroidStudio,Minecraft和IntelliJIDEA開發(fā)工具,其中OpenJDK不太受歡迎;

5.在響應(yīng)性和JVM性能方面,OracleJDK與OpenJDK相比提供了更好的性能;

6.OracleJDK不會(huì)為即將發(fā)布的版本提供長(zhǎng)期支持,用戶每次都必須通過(guò)更新到最新版本獲得支持來(lái)獲取最新版本;

7.OracleJDK根據(jù)二進(jìn)制代碼許可協(xié)議獲得許可,而OpenJDK根據(jù)GPLv2許可獲得許可。

5.Java和C++的區(qū)別

我知道很多人沒學(xué)過(guò)C++,但是面試官就是沒事喜歡拿咱們Java和C++比呀!沒辦法?。。【退銢]學(xué)過(guò)C++,也要記下來(lái)!

?? ? 都是面向?qū)ο蟮恼Z(yǔ)言,都支持封裝、繼承和多態(tài)

?? ? Java? 不提供指針來(lái)直接訪問(wèn)內(nèi)存,程序內(nèi)存更加安全

?? ? Java的類是單繼承的,C++支持多重繼承;雖然Java的類不可以多繼承,但是接口可以多繼承。

?? ? Java有自動(dòng)內(nèi)存管理機(jī)制,不需要程序員手動(dòng)釋放無(wú)用內(nèi)存

6.什么是Java程序的主類應(yīng)用程序和小程序的主類有何不同

一個(gè)程序中可以有多個(gè)類,但只能有一個(gè)類是主類。在 Java 應(yīng)用程序中,這個(gè)主類是指包含 main()方法的類。而在 Java 小程序中,這個(gè)主類是一個(gè)繼承自系統(tǒng)類 JApplet 或 Applet 的子類。應(yīng)用程序的主類不一定要求是 public類,但小程序的主類要求必須是 public 類。主類是 Java 程序執(zhí)行的入口點(diǎn)。

7. Java 應(yīng)用程序與小程序之間有那些差別

簡(jiǎn)單說(shuō)應(yīng)用程序是從主線程啟動(dòng)(也就是 main() 方法)。applet 小程序沒有main 方法,主要是嵌在瀏覽器頁(yè)面上運(yùn)行(調(diào)用 init()線程或者 run()來(lái)啟動(dòng)),嵌入瀏覽器這點(diǎn)跟 flash 的小游戲類似。

8. 字符型常量和字符串常量的區(qū)別

1. 形式上: 字符常量是單引號(hào)引起的一個(gè)字符 字符串常量是雙引號(hào)引起的若干個(gè)字符

2. 含義上: 字符常量相當(dāng)于一個(gè)整形值( ASCII 值),可以參加表達(dá)式運(yùn)算 字符串常量代表一個(gè)地址值(該字符串在內(nèi)存中存放位置)

3. 占內(nèi)存大小 字符常量只占 2 個(gè)字節(jié) 字符串常量占若干個(gè)字節(jié)(至少一個(gè)字符結(jié)束標(biāo)志) (注意: char 在 Java 中占兩個(gè)字節(jié))

9. 構(gòu)造器 Constructor 是否可被 override

在講繼承的時(shí)候我們就知道父類的私有屬性和構(gòu)造方法并不能被繼承,所以Constructor 也就不能被 override(重寫),但是可以 overload(重載),所以你可以看到一個(gè)類中有多個(gè)構(gòu)造函數(shù)的情況。

10. 重載和重寫的區(qū)別

重載: 發(fā)生在同一個(gè)類中,方法名必須相同,參數(shù)類型不同、個(gè)數(shù)不同、順序不同,方法返回值和訪問(wèn)修飾符可以不同,發(fā)生在編譯時(shí)。

重寫: 發(fā)生在父子類中,方法名、參數(shù)列表必須相同,返回值范圍小于等于父類,拋出的異常范圍小于等于父類,訪問(wèn)修飾符

范圍大于等于父類;如果父類方法訪問(wèn)修飾符為 private 則子類就不能重寫該方法。

11. Java 面向?qū)ο缶幊倘筇匦? 封裝 繼承 多態(tài)

封裝

封裝把一個(gè)對(duì)象的屬性私有化,同時(shí)提供一些可以被外界訪問(wèn)的屬性的方法,如果屬性不想被外界訪問(wèn),我們大可不必提供法給外界訪問(wèn)。但是如果一個(gè)類沒有提供給外界訪問(wèn)的方法,那么這個(gè)類也沒有什么意義了。

繼承

繼承是使用已存在的類的定義作為基礎(chǔ)建立新類的技術(shù),新類的定義可以增加新的數(shù)據(jù)或新的功能,也可以用父類的功能,不能選擇性地繼承父類。通過(guò)使用繼承我們能夠非常方便地復(fù)用以前的代碼。

關(guān)于繼承如下 3 點(diǎn)請(qǐng)記?。?/p>

1. 子類擁有父類非 private 的屬性和方法。

2. 子類可以擁有自己屬性和方法,即子類可以對(duì)父類進(jìn)行擴(kuò)展。

3. 子類可以用自己的方式實(shí)現(xiàn)父類的方法。

多態(tài)

所謂多態(tài)就是指程序中定義的引用變量所指向的具體類型和通過(guò)該引用變量發(fā)出的方法調(diào)用在編程時(shí)并不確定,而是在程序運(yùn)行期間才確定,即一個(gè)引用變量倒底會(huì)指向哪個(gè)類的實(shí)例對(duì)象,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類中實(shí)現(xiàn)的方法,必須在由程序運(yùn)行期間才能決定。在 Java 中有兩種形式可以實(shí)現(xiàn)多態(tài):繼承(多個(gè)子類對(duì)同一方法的重寫)和接口(實(shí)現(xiàn)接口并覆蓋接口中同一方法)。

12. String StringBuffer 和 StringBuilder 的區(qū)別是什么 String 為什么是不可變的

可變性

簡(jiǎn)單的來(lái)說(shuō):String 類中使用 final 關(guān)鍵字字符數(shù)組保存字符串,privatefinal char value[],所以 String 對(duì)象是不可變的。而 StringBuilder 與StringBuffer 都繼承自 AbstractStringBuilder 類,在 AbstractStringBuilder 中也是使用字符數(shù)組保存字符串 char[]value 但是沒有用 final 關(guān)鍵字修飾,所以這兩種對(duì)象都是可變的。

StringBuilder 與 StringBuffer 的構(gòu)造方法都是調(diào)用父類構(gòu)造方法也就是

AbstractStringBuilder 實(shí)現(xiàn)的,大家可以自行查閱源碼。

AbstractStringBuilder.java

abstract class AbstractStringBuilder implements Appendable, CharSequence {

char[] value;

int count;

AbstractStringBuilder() {

}

AbstractStringBuilder(int capacity) {

value = new char[capacity];

}

線程安全性

String 中的對(duì)象是不可變的,也就可以理解為常量,線程安全。AbstractStringBuilder 是 StringBuilder 與 StringBuffer 的公共父類,定義了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 對(duì)方法加了同步鎖或者對(duì)調(diào)用的方法加了同步鎖,所以是線程安全的。StringBuilder 并沒有對(duì)方法進(jìn)行加同步鎖,所以是非線程安全的。

性能

每次對(duì) String 類型進(jìn)行改變的時(shí)候,都會(huì)生成一個(gè)新的 String 對(duì)象,然后將指針指向新的 String 對(duì)象。StringBuffer 每次都會(huì)對(duì) StringBuffer 對(duì)象本身進(jìn)行操作,而不是生成新的對(duì)象并改變對(duì)象引用。相同情況下使用StringBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的風(fēng)險(xiǎn)。

對(duì)于三者使用的總結(jié):

1. 操作少量的數(shù)據(jù) = String

2. 單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) = StringBuilder

3. 多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) = StringBuffer

13. 自動(dòng)裝箱與拆箱

裝箱:將基本類型用它們對(duì)應(yīng)的引用類型包裝起來(lái);

拆箱:將包裝類型轉(zhuǎn)換為基本數(shù)據(jù)類型;

14. 在一個(gè)靜態(tài)方法內(nèi)調(diào)用一個(gè)非靜態(tài)成員為什么是非法的

由于靜態(tài)方法可以不通過(guò)對(duì)象進(jìn)行調(diào)用,因此在靜態(tài)方法里,不能調(diào)用其他非靜態(tài)變量,也不可以訪問(wèn)非靜態(tài)變量成員。

15. 在 Java 中定義一個(gè)不做事且沒有參數(shù)的構(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)造方法。

16. import java 和 javax 有什么區(qū)別

剛開始的時(shí)候 JavaAPI 所必需的包是 java 開頭的包,javax 當(dāng)時(shí)只是擴(kuò)展API 包來(lái)說(shuō)使用。然而隨著時(shí)間的推移,javax 逐漸的擴(kuò)展成為 Java API 的組成部分。但是,將擴(kuò)展從 javax 包移動(dòng)到 java 包將是太麻煩了,最終會(huì)破壞一堆現(xiàn)有的代碼。因此,最終決定 javax 包將成為標(biāo)準(zhǔn) API 的一部分。所以,實(shí)際上 java 和 javax 沒有區(qū)別。這都是一個(gè)名字。

17. 接口和抽象類的區(qū)別是什么

1. 接口的方法默認(rèn)是 public,所有方法在接口中不能有實(shí)現(xiàn)(Java 8 開始接口方法可以有默認(rèn)實(shí)現(xiàn)),抽象類可以有非抽象的方法

2. 接口中的實(shí)例變量默認(rèn)是 final 類型的,而抽象類中則不一定

3. 一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,但最多只能實(shí)現(xiàn)一個(gè)抽象類

4. 一個(gè)類實(shí)現(xiàn)接口的話要實(shí)現(xiàn)接口的所有方法,而抽象類不一定

5. 接口不能用 new 實(shí)例化,但可以聲明,但是必須引用一個(gè)實(shí)現(xiàn)該接口的對(duì)象 從設(shè)計(jì)層面來(lái)說(shuō),抽象是對(duì)類的抽象,是一種模板設(shè)計(jì),接口是行為的抽象,是一種行為的規(guī)范。

18. 成員變量與局部變量的區(qū)別有那些

1. 從語(yǔ)法形式上,看成員變量是屬于類的,而局部變量是在方法中定義的變量或是方法的參數(shù);成員變量可以被public,private,static 等修飾符所修飾,而局部變量不能被訪問(wèn)控制修飾符及 static 所修飾;但是,成員變量和局部變量都能被 final 所修飾;

2. 從變量在內(nèi)存中的存儲(chǔ)方式來(lái)看,成員變量是對(duì)象的一部分,而對(duì)象存在于堆內(nèi)存,局部變量存在于棧內(nèi)存

3. 從變量在內(nèi)存中的生存時(shí)間上看,成員變量是對(duì)象的一部分,它隨著對(duì)象的創(chuàng)建而存在,而局部變量隨著方法的調(diào)用而自動(dòng)消失。

4. 成員變量如果沒有被賦初值,則會(huì)自動(dòng)以類型的默認(rèn)值而賦值(一種情況例外被 final 修飾的成員變量也必須顯示地賦值);而局部變量則不會(huì)自動(dòng)賦值。

19. 創(chuàng)建一個(gè)對(duì)象用什么運(yùn)算符?對(duì)象實(shí)體與對(duì)象引用有何不同?

new 運(yùn)算符,new 創(chuàng)建對(duì)象實(shí)例(對(duì)象實(shí)例在堆內(nèi)存中),對(duì)象引用指向?qū)ο髮?shí)例(對(duì)象引用存放在棧內(nèi)存中)。一個(gè)對(duì)象引用可以指向 0 個(gè)或 1 個(gè)對(duì)象(一根繩子可以不系氣球,也可以系一個(gè)氣球);一個(gè)對(duì)象可以有 n 個(gè)引用指向它(可以用 n 條繩子系住一個(gè)氣球)。

20. 什么是方法的返回值?返回值在類的方法里的作用是什么?

方法的返回值是指我們獲取到的某個(gè)方法體中的代碼執(zhí)行后產(chǎn)生的結(jié)果?。ㄇ疤崾窃摲椒赡墚a(chǎn)生結(jié)果)。返回值的作用:接收出結(jié)果,使得它可以用于其他的操作!

21. 一個(gè)類的構(gòu)造方法的作用是什么 若一個(gè)類沒有聲明構(gòu)造方法,該程序能正確執(zhí)行嗎 ?為什么?

主要作用是完成對(duì)類對(duì)象的初始化工作。可以執(zhí)行。因?yàn)橐粋€(gè)類即使沒有聲明構(gòu)造方法也會(huì)有默認(rèn)的不帶參數(shù)的構(gòu)造方法。

22. 構(gòu)造方法有哪些特性

1. 名字與類名相同;

2. 沒有返回值,但不能用 void 聲明構(gòu)造函數(shù);

3. 生成類的對(duì)象時(shí)自動(dòng)執(zhí)行,無(wú)需調(diào)用。

23. 靜態(tài)方法和實(shí)例方法有何不同

1. 在外部調(diào)用靜態(tài)方法時(shí),可以使用"類名.方法名"的方式,也可以使用"對(duì)象名.方法名"的方式。而實(shí)例方法只有后面這種方式。也就是說(shuō),調(diào)用靜態(tài)方法可以無(wú)需創(chuàng)建對(duì)象。

2. 靜態(tài)方法在訪問(wèn)本類的成員時(shí),只允許訪問(wèn)靜態(tài)成員(即靜態(tài)成員變量和靜態(tài)方法),而不允許訪問(wèn)實(shí)例成員變量和實(shí)例方法;實(shí)例方法則無(wú)此限制.

24. 對(duì)象的相等與指向他們的引用相等,兩者有什么不同?

對(duì)象的相等,比的是內(nèi)存中存放的內(nèi)容是否相等。而引用相等,比較的是他們指向的內(nèi)存地址是否相等。

25. 在調(diào)用子類構(gòu)造方法之前會(huì)先調(diào)用父類沒有參數(shù)的構(gòu)造方法,其目的是?

幫助子類做初始化工作。

26. == 與 equals(重要)

== : 它的作用是判斷兩個(gè)對(duì)象的地址是不是相等。即,判斷兩個(gè)對(duì)象是不是同一個(gè)對(duì)象。(基本數(shù)據(jù)類型==比較的是值,引用數(shù)據(jù)類型==比較的是內(nèi)存地址)equals() : 它的作用也是判斷兩個(gè)對(duì)象是否相等。但它一般有兩種使用情況:

? 情況 1:類沒有覆蓋 equals() 方法。則通過(guò) equals() 比較該類的兩個(gè)對(duì)象時(shí),等價(jià)于通過(guò)“==”比較這兩個(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)) // https://www.xiaoyuani.com/?true

System.out.println("aEQb");

if (42 == 42.0) { // true

System.out.println("true");

}

}

}

說(shuō)明:

? String 中的 equals 方法是被重寫過(guò)的,因?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ì)象。

27. hashCode 與 equals(重要)

面試官可能會(huì)問(wèn)你:“你重寫過(guò) hashcode 和 equals 么,為什么重寫 equals時(shí)必須重寫 hashCode 方法?”

hashCode()介紹

hashCode() 的作用是獲取哈希碼,也稱為散列碼;它實(shí)際上是返回一個(gè) int 整數(shù)。這個(gè)哈希碼的作用是確定該對(duì)象在哈希表中的索引位置。hashCode() 定義在 JDK 的 Object.java 中,這就意味著 Java 中的任何類都包含有 hashCode() 函數(shù)。

散列表存儲(chǔ)的是鍵值對(duì)(key-value),它的特點(diǎn)是:能根據(jù)“鍵”快速的檢索出對(duì)應(yīng)的“值”。這其中就利用到了散列碼?。梢钥焖僬业剿枰膶?duì)象)

為什么要有 hashCode

我們以“HashSet 如何檢查重復(fù)”為例子來(lái)說(shuō)明為什么要有 hashCode:

當(dāng)你把對(duì)象加入 HashSet 時(shí),HashSet 會(huì)先計(jì)算對(duì)象的 hashcode 值來(lái)判斷對(duì)象加入的位置,同時(shí)也會(huì)與其他已經(jīng)加入的對(duì)象的 hashcode 值作比較,如果沒有相符的 hashcode,HashSet 會(huì)假設(shè)對(duì)象沒有重復(fù)出現(xiàn)。但是如果發(fā)現(xiàn)有相同 hashcode 值的對(duì)象,這時(shí)會(huì)調(diào)用 equals()方法來(lái)檢查 hashcode 相等的對(duì)象是否真的相同。如果兩者相同,HashSet 就不會(huì)讓其加入操作成功。如果不同的話,就會(huì)重新散列到其他位置。(摘自我的 Java 啟蒙書《Headfirst java》第二版)。這樣我們就大大減少了 equals 的次數(shù),相應(yīng)就大大提高了執(zhí)行速度。

hashCode()與 equals()的相關(guān)規(guī)定

1. 如果兩個(gè)對(duì)象相等,則 hashcode 一定也是相同的

2. 兩個(gè)對(duì)象相等,對(duì)兩個(gè)對(duì)象分別調(diào)用 equals 方法都返回 true

3. 兩個(gè)對(duì)象有相同的 hashcode 值,它們也不一定是相等的

4. 因此,equals 方法被覆蓋過(guò),則 hashCode 方法也必須被覆蓋

5. hashCode() 的默認(rèn)行為是對(duì)堆上的對(duì)象產(chǎn)生獨(dú)特值。如果沒有重寫hashCode(),則該 class 的兩個(gè)對(duì)象無(wú)論如何都不會(huì)相等(即使這兩個(gè)對(duì)象指向相同的數(shù)據(jù))

28. 簡(jiǎn)述線程,程序、進(jìn)程的基本概念。以及他們之間關(guān)系是什么

線程與進(jìn)程相似,但線程是一個(gè)比進(jìn)程更小的執(zhí)行單位。一個(gè)進(jìn)程在其執(zhí)行的過(guò)程中可以產(chǎn)生多個(gè)線程。與進(jìn)程不同的是同類的多個(gè)線程共享同一塊內(nèi)存空間和一組系統(tǒng)資源,所以系統(tǒng)在產(chǎn)生一個(gè)線程,或是在各個(gè)線程之間作切換工作時(shí),負(fù)擔(dān)要比進(jìn)程小得多,也正因?yàn)槿绱耍€程也被稱為輕量級(jí)進(jìn)程。

程序是含有指令和數(shù)據(jù)的文件,被存儲(chǔ)在磁盤或其他的數(shù)據(jù)存儲(chǔ)設(shè)備中,也就是說(shuō)程序是靜態(tài)的代碼。

進(jìn)程是程序的一次執(zhí)行過(guò)程,是系統(tǒng)運(yùn)行程序的基本單位,因此進(jìn)程是動(dòng)態(tài)的。系統(tǒng)運(yùn)行一個(gè)程序即是一個(gè)進(jìn)程從創(chuàng)建,運(yùn)行到消亡的過(guò)程。簡(jiǎn)單來(lái)說(shuō),一個(gè)進(jìn)程就是一個(gè)執(zhí)行中的程序,它在計(jì)算機(jī)中一個(gè)指令接著一個(gè)指令地執(zhí)行著,同時(shí),每個(gè)進(jìn)程還占有某些系統(tǒng)資源如 CPU 時(shí)間,內(nèi)存空間,文件,文件,輸入輸出設(shè)備的使用權(quán)等等。換句話說(shuō),當(dāng)程序在執(zhí)行時(shí),將會(huì)被操作系統(tǒng)載入內(nèi)存中。 線程是進(jìn)程劃分成的更小的運(yùn)行單位。線程和進(jìn)程最大的不同在于基本上各進(jìn)程是獨(dú)立的,而各線程則不一定,因?yàn)橥贿M(jìn)程中的線程極有可能會(huì)相互影響。從另一角度來(lái)說(shuō),進(jìn)程屬于操作系統(tǒng)的范疇,主要是同一段時(shí)間內(nèi),可以同時(shí)執(zhí)行一個(gè)以上的程序,而線程則是在同一程序內(nèi)幾乎同時(shí)執(zhí)行一個(gè)以上的程序段。

29. 線程有哪些基本狀態(tài)?

參考《Java 并發(fā)編程藝術(shù)》4.1.4 節(jié)。

Java 線程在運(yùn)行的生命周期中的指定時(shí)刻只可能處于下面 6 種不同狀態(tài)的其中一個(gè)狀態(tài)。

線程在生命周期中并不是固定處于某一個(gè)狀態(tài)而是隨著代碼的執(zhí)行在不同狀態(tài)之間切換。

30 關(guān)于 final 關(guān)鍵字的一些總結(jié)

final 關(guān)鍵字主要用在三個(gè)地方:變量、方法、類。

1. 對(duì)于一個(gè) final 變量,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始化之后便不能更改;如果是引用類型的變量,則在對(duì)其初始化之后便不能再讓其指向另一個(gè)對(duì)象。

2. 當(dāng)用 final 修飾一個(gè)類時(shí),表明這個(gè)類不能被繼承。final 類中的所有成員方法都會(huì)被隱式地指定為 final 方法。

3. 使用 final 方法的原因有兩個(gè)。第一個(gè)原因是把方法鎖定,以防任何繼承類修改它的含義;第二個(gè)原因是效率。在早期的 Java 實(shí)現(xiàn)版本中,會(huì)將final 方法轉(zhuǎn)為內(nèi)嵌調(diào)用。但是如果方法過(guò)于龐大,可能看不到內(nèi)嵌調(diào)用帶來(lái)的任何性能提升(現(xiàn)在的 Java 版本已經(jīng)不需要使用 final 方法進(jìn)行這些優(yōu)化了)。類中所有的 private 方法都隱式地指定為 final。

31 Java 序列化中如果有些字段不想進(jìn)行序列化 怎么辦

對(duì)于不想進(jìn)行序列化的變量,使用 transient 關(guān)鍵字修飾。

transient 關(guān)鍵字的作用是:阻止實(shí)例中那些用此關(guān)鍵字修飾的的變量序列化;

當(dāng)對(duì)象被反序列化時(shí),被 transient 修飾的變量值不會(huì)被持久化和恢復(fù)。

transient 只能修飾變量,不能修飾類和方法。

32 獲取用鍵盤輸入常用的的兩種方法

方法 1:通過(guò) Scanner

Scanner input = new Scanner(System.in);

String s = input.nextLine();

input.close();

方法 2:通過(guò) BufferedReaderBufferedReader input = new BufferedReader(new InputStreamReader(System.in));

String s = input.readLine();

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容