Java基础面试典籍60+ | 大别山码将
java基礎(chǔ)
面向?qū)ο蠛兔嫦蜻^程的區(qū)別
面向過程:比面向?qū)ο笮阅芨?#xff1b;面向過程以步驟劃分問題,就是分析出解決問題所需要的步驟,然后用函數(shù)把這些步驟一步一步實(shí)現(xiàn),使用的時候一個一個依次調(diào)用就可以了(蛋炒飯)
面向?qū)ο?/strong>:比面向過程易維護(hù),易復(fù)用,易拓展;面向?qū)ο笠怨δ軇澐謫栴},是把構(gòu)成問題事務(wù)分解成各個對象,建立對象的目的不是為了完成一個步驟,而是為了描敘某個事物在整個解決問題的步驟中的行為。(蓋澆飯)
面向過程
優(yōu)點(diǎn):性能比面向?qū)ο蟾?#xff0c;因?yàn)轭愓{(diào)用時需要實(shí)例化,開銷比較大,比較消耗資源;比如單片機(jī)、嵌入式開發(fā)、
Linux/Unix等一般采用面向過程開發(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):性能比面向過程低
java語言有哪些特點(diǎn)
-
簡單易學(xué);
-
?向?qū)ο?#xff08;封裝,繼承,多態(tài));
-
平臺?關(guān)性( Java 虛擬機(jī)實(shí)現(xiàn)平臺?關(guān)性);
-
可靠性;
-
安全性;
-
?持多線程( C++ 語?沒有內(nèi)置的多線程機(jī)制,因此必須調(diào)?操作系統(tǒng)的多線程功能來進(jìn)?多線程程序設(shè)計(jì),? Java 語?卻提供了多線程?持);
-
?持?絡(luò)編程并且很?便( Java 語?誕?本身就是為簡化?絡(luò)編程設(shè)計(jì)的,因此 Java 語?不僅?持?絡(luò)編程?且很?便);
-
編譯與解釋并存;
java如何實(shí)現(xiàn)平臺無關(guān)
平臺無關(guān)性就是一種語言在計(jì)算機(jī)上的運(yùn)行不受平臺的約束,一次編譯,到處執(zhí)行。Java減少了開發(fā)和部署到多個平臺的成本和時間
- Java語言規(guī)范
- 通過規(guī)定Java語言中基本數(shù)據(jù)類型的取值范圍和行為
- Class文件
- 所有Java文件要編譯成統(tǒng)一的Class文件
- Java虛擬機(jī)
- 通過Java虛擬機(jī)將Class文件轉(zhuǎn)成對應(yīng)平臺的二進(jìn)制文件等
java文件-》class文件-》二進(jìn)制文件
JVM: Java編譯器可生成與計(jì)算機(jī)體系結(jié)構(gòu)無關(guān)的字節(jié)碼指令,.class 字節(jié)碼文件面向虛擬機(jī),不面向任何具體操作系統(tǒng)。所以.class字節(jié)碼文件不僅可以輕易地在任何機(jī)器上解釋執(zhí)行,還可以動態(tài)地轉(zhuǎn)換成本地機(jī)器代碼,轉(zhuǎn)換是由 JVM 實(shí)現(xiàn)的,JVM 是平臺相關(guān)的,屏蔽了不同操作系統(tǒng)的差異。
java的安全性體現(xiàn)在哪里?
1、Java 不提供指針來直接訪問內(nèi)存,使用引用取代了指針,程序內(nèi)存更加安全
2、擁有一套異常處理機(jī)制,使用關(guān)鍵字 throw、throws、try、catch、finally
3、強(qiáng)制類型轉(zhuǎn)換需要符合一定規(guī)則
4、字節(jié)碼傳輸使用了加密機(jī)制
5、運(yùn)行環(huán)境提供保障機(jī)制:字節(jié)碼校驗(yàn)器->類裝載器->運(yùn)行時內(nèi)存布局->文件訪問限制
6、不用程序員顯示控制內(nèi)存釋放,JVM 有垃圾回收機(jī)制
JVM,JDK和JRE之間的區(qū)別
首先說明三者的關(guān)系是:
JDK(Java Develepment Kit)Java開發(fā)工具包
JRE(Java RunTime Environment)Java運(yùn)行時環(huán)境
JVM(Java Virtual Machine)Java虛擬機(jī)
JDK = JRE + Java工具s + Java基礎(chǔ)類庫
JRE = JVM + JVM工作所需的類庫
JVM是運(yùn)? Java 字節(jié)碼的虛擬機(jī)。JVM 有針對不同系統(tǒng)的特定實(shí)現(xiàn)(Windows,Linux,macOS),?的是使?相同的字節(jié)碼,它們都會給出相同的結(jié)果。字節(jié)碼和不同系統(tǒng)的 JVM 實(shí)現(xiàn)是 Java 語?“?次編譯,隨處可以運(yùn)?”的關(guān)鍵所在。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-KDE1ek6O-1632494423932)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210831091740889.png)]
JRE是運(yùn)行基于Java語言編寫的程序所不可缺少的運(yùn)行環(huán)境。也是通過它,Java的開發(fā)者才得以將自己開發(fā)的程序發(fā)布到用戶手中,讓用戶使用。
如果你只是為了運(yùn)??下 Java 程序的話,那么你只需要安裝 JRE 就可以了。如果你需要進(jìn)??些 Java 編程??的?作,那么你就需要安裝 JDK 了。但是,這不是絕對的。有時,即使您不打算在計(jì)算機(jī)上進(jìn)?任何 Java 開發(fā),仍然需要安裝 JDK。例如,如果要使? JSP 部署 Web 應(yīng)?程序,那么從技術(shù)上講,您只是在應(yīng)?程序服務(wù)器中運(yùn)? Java 程序。那你為什么需要 JDK 呢?因?yàn)閼?yīng)?程序服務(wù)器會將 JSP 轉(zhuǎn)換為 Java servlet,并且需要使? JDK 來編譯 servlet。
JDK是Java開發(fā)工具包,JDK是整個JAVA的核心,包括了Java運(yùn)行環(huán)境JRE(Java Runtime Envirnment)、一堆Java工具(javac/java/jdb等)和Java基礎(chǔ)的類庫(即Java API 包括rt.jar)。它能夠創(chuàng)建和編譯程序。
Oracle JDK和OpenJDK對比
- OpenJDK 是?個參考模型并且是完全開源的,? Oracle JDK 是 OpenJDK 的?個實(shí)現(xiàn),并不是完全開源的;
- Oracle JDK ? OpenJDK 更穩(wěn)定。OpenJDK 和 Oracle JDK 的代碼?乎相同,但 OracleJDK 有更多的類和?些錯誤修復(fù)。因此,如果您想開發(fā)企業(yè)/商業(yè)軟件,我建議您選擇Oracle JDK,因?yàn)樗?jīng)過了徹底的測試和穩(wěn)定。某些情況下,有些?提到在使? OpenJDK可能會遇到了許多應(yīng)?程序崩潰的問題,但是,只需切換到 Oracle JDK 就可以解決問題;
- 在響應(yīng)性和 JVM 性能??,Oracle JDK 比 OpenJDK 相?性能更好;
- Oracle JDK 不會為即將發(fā)布的版本提供?期?持,?戶每次都必須通過更新到最新版本獲得?持來獲取最新版本;
- Oracle JDK 根據(jù)?進(jìn)制代碼許可協(xié)議獲得許可,? OpenJDK 根據(jù) GPL v2 許可獲得許可。
java和c++區(qū)別
- 都是?向?qū)ο蟮恼Z?,都?持封裝、繼承和多態(tài)
- Java 不提供指針來直接訪問內(nèi)存,程序內(nèi)存更加安全
- Java 的類是單繼承的,C++ ?持多重繼承;雖然 Java 的類不可以多繼承,但是接?可以多繼承。
- Java 有?動內(nèi)存管理機(jī)制,不需要程序員?動釋放??內(nèi)存
- 在 C 語?中,字符串或字符數(shù)組最后都會有?個額外的字符‘\0’來表示結(jié)束。但是,Java 語?中沒有結(jié)束符這?概念。
字符型常量和字符串常量區(qū)別
-
形式上: 字符常量是單引號引起的?個字符; 字符串常量是雙引號引起的若?個字符
-
含義上: 字符常量相當(dāng)于?個整型值( ASCII 值), 字符串常量代表?個地址值(該字符串在內(nèi)存中存放位置)
-
字符常量只占 2 個字節(jié); 字符串常量占若?個字節(jié)
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-6AkzKylu-1632494423957)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210831093557593.png)]
什么是反射?
JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法,對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性,這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機(jī)制。在 java 中,只要給定類的名字, 那么就可以通過反射機(jī)制來獲得類的所有信息。
- Java 的動態(tài)就體現(xiàn)在這。通過反射我們可以實(shí)現(xiàn)動態(tài)裝配,降低代碼的耦合度;動態(tài)代理等。反射的過度使用會嚴(yán)重消耗系統(tǒng)資源。
**JDK 中 java.lang.Class 類,就是為了實(shí)現(xiàn)反射提供的核心類之一。**反射使用的不當(dāng),對性能影響比較大,一般項(xiàng)目中直接使用較少。
反射主要用于底層的框架中,Spring 中就大量使用了反射,比如:
- 用 IoC 來注入和組裝 bean
- 動態(tài)代理、面向切面、bean 對象中的方法替換與增強(qiáng),也使用了反射
- 定義的注解,也是通過反射查找
還用于:在編譯時無法知道該對象或類可能屬于哪些類,用作程序在運(yùn)行時獲取對象和類的信息
優(yōu)點(diǎn):提高了 Java 程序的靈活性和擴(kuò)展性,降低耦合性,提高自適應(yīng)能力。
缺點(diǎn)
使用反射的性能較低。 java 反射是要解析字節(jié)碼,將內(nèi)存中的對象進(jìn)行解析。
-
性能問題:反射是一種解釋操作,遠(yuǎn)慢于直接代碼。因此反射機(jī)制主要用在對靈活性和擴(kuò)展性要求很高的系統(tǒng)框架上,普通程序不建議使用
-
模糊程序內(nèi)部邏輯:反射繞過了源代碼,無法再源代碼中看到程序的邏輯,會帶來維護(hù)問題
-
增大了復(fù)雜性:反射代碼比同等功能的直接代碼更復(fù)雜
解決方案:
???? 1.由于 JDK 的安全檢查耗時較多,所以通過 setAccessible(true)的方式關(guān)閉安全檢查 來(取消對訪問控制修飾符的檢查)提升反射速度。
???? 2.需要多次動態(tài)創(chuàng)建一個類的實(shí)例的時候,有緩存的寫法會比沒有緩存要快很多:
???? 3.ReflectASM 工具類 ,通過字節(jié)碼生成的方式加快反射速度。
(2)使用反射相對來說不安全,破壞了類的封裝性,可以通過反射獲取這個 類的私有方法和屬性。
反射的實(shí)現(xiàn)方式:
在 Java 中實(shí)現(xiàn)反射最重要的一步, 也是第一步就是獲取 Class 對象, 得到Class 對象后可以通過該對象調(diào)用相應(yīng)的方法來獲取該類中的屬性、方法以及調(diào)用該類中的方法。
???? 有 4 種方法可以得到 Class 對象:
???? 1.Class.forName(“類的路徑”);
???? 2.類名.class。
???? 3.對象名.getClass()。
???? 4.如果是基本類型的包裝類,則可以通過調(diào)用包裝類的 Type 屬性來獲得該包裝類的 Class 對象。
???? 例如: Class<?> clazz = Integer.TYPE;
Class類的作用是什么?如何獲取Class對象?
Class 類是 Java 反射機(jī)制的起源和入口,用于獲取與類相關(guān)的各種信息,提供了獲取類信息的相關(guān)方法。
什么是泛型?為什么要使用泛型?
參數(shù)化類型,將類型由具體的類型參數(shù)化,具有在多種數(shù)據(jù)類型上皆可操作的含意,與模板有些相似。
為什么要用泛型?
- 使用泛型編寫的程序代碼,要比使用 Object 變量再進(jìn)行強(qiáng)制類型轉(zhuǎn)換的代碼,具有更好的安全性和可讀性。
- 多種數(shù)據(jù)類型執(zhí)行相同的代碼使用泛型可以復(fù)用代碼。
比如集合類使用泛型,取出和操作元素時無需進(jìn)行類型轉(zhuǎn)換,避免出現(xiàn) java.lang.ClassCastException 異常
String s = new String(“xyz”);創(chuàng)建幾個String對象?
兩個或一個
- 第一次調(diào)用 new String(“xyz”); 時,會在堆內(nèi)存中創(chuàng)建一個字符串對象,同時在字符串常量池中創(chuàng)建一個對象 “xyz”
- 第二次調(diào)用 new String(“xyz”); 時,只會在堆內(nèi)存中創(chuàng)建一個字符串對象,指向之前在字符串常量池中創(chuàng)建的 “xyz”
構(gòu)造器Constructor是否可被override(重寫)?
Constructor 不能被 override(重寫),但是可以 overload(重載),所以你可以看到?個類中有多個構(gòu)造函數(shù)的情況。
重載和重寫的區(qū)別
重載就是同一個類中多個同名方法根據(jù)不同的傳參來執(zhí)行不同的邏輯處理,是一個類中多態(tài)性的一種表現(xiàn)。有不同的參數(shù)列表(靜態(tài)多態(tài)性)。多個用戶使用一個非開源項(xiàng)目,每個用戶使用它做不同的事情
重寫就是子類對父類方法的重新改造,外部樣子不能改變,內(nèi)部邏輯可以改變, 是父類與子類之間多態(tài)性的一種表現(xiàn)。相同參數(shù),不同實(shí)現(xiàn)(動態(tài)多態(tài)性)。多個用戶使用一個開源項(xiàng)目,每個用戶都可以對其進(jìn)行修改
?法的重寫要遵循“兩同兩???”:
- “兩同”即?法名相同、形參列表相同;
- “兩?”指的是?類?法返回值類型應(yīng)??類?法返回值類型更?或相等,?類?法聲明拋出的異常類應(yīng)??類?法聲明拋出的異常類更?或相等;
- “??”指的是?類?法的訪問權(quán)限應(yīng)??類?法的訪問權(quán)限更?或相等
構(gòu)造方法可以重載,不可重寫
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-a0UJpWuG-1632494423962)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210831093854285.png)]
靜態(tài)成員變量和非靜態(tài)成員變量
-
別名不同:非靜態(tài)成員變量也稱為實(shí)例變量;靜態(tài)變量稱為類變量
-
生命周期不同:非靜態(tài)成員變量隨著對象的創(chuàng)建而存在;靜態(tài)成員變量隨著類的加載而存在
-
調(diào)用方式不同:非靜態(tài)成員變量用 對象名.變量名 調(diào)用;靜態(tài)成員變量用 類名.變量名,JDK1.7 以后也能用對象名.變量名調(diào)用
-
數(shù)據(jù)存儲位置不同:成員變量數(shù)據(jù)存儲在堆內(nèi)存的對象中,對象的特有數(shù)據(jù);JDK1.6 靜態(tài)變量數(shù)據(jù)存儲在方法區(qū)(共享數(shù)據(jù)區(qū))的靜態(tài)區(qū),對象的共享數(shù)據(jù),JDK1.7 靜態(tài)變量移到堆中存儲
Java面向?qū)ο缶幊倘筇匦?#xff1a;封裝,繼承,多態(tài)
封裝:是把?個對象的屬性私有化,同時提供?些可以被外界訪問的屬性的?法,如果屬性不想被外界訪問,我們?可不必提供?法給外界訪問。
繼承:是使?已存在的類的定義作為基礎(chǔ)建?新類的技術(shù),新類的定義可以增加新的數(shù)據(jù)或新的功能,也可以??類的功能,但不能選擇性地繼承?類。通過使?繼承我們能夠?常?便地復(fù)?以前的代碼。
關(guān)于繼承如下 3 點(diǎn)請記住:
- ?類擁有?類對象所有的屬性和?法(包括私有屬性和私有?法),但是?類中的私有屬性和?法?類是?法訪問,只是擁有。
- ?類可以擁有??屬性和?法,即?類可以對?類進(jìn)?擴(kuò)展。
- ?類可以???的?式實(shí)現(xiàn)?類的?法。
多態(tài):多態(tài)是同一個行為具有多個不同表現(xiàn)形式或形態(tài)的能力。多態(tài)就是同一個接口,使用不同的實(shí)例而執(zhí)行不同操作。(比如打印機(jī)都會打印這個行為,而使用黑白打印機(jī)打印會打印出黑白的圖文,使用彩色打印機(jī)打印則會打印出彩色的圖文。)(再比如地震來臨前都會引發(fā)動物叫,如果是狗就會吠叫,如果是雞就會啼叫)。在 Java 中有兩種形式可以實(shí)現(xiàn)多態(tài):繼承(多個?類對同??法的重寫)和接?(實(shí)現(xiàn)接?并覆蓋接?中同??法)。
String,StringBuffer和StringBuilder三者區(qū)別
String 是 Java 語言非常基礎(chǔ)和重要的類,提供了構(gòu)造和管理字符串的各種基本邏輯。String 中的對象是不可變的,也就可以理解為常量,保證了線程安全。
StringBuffer 對?法加了同步鎖,所以是線程安全的。性能低
StringBuilder 并沒有對?法進(jìn)?加同步鎖,所以是**?線程安全的。**性能高,有效減小了開銷
對于三者使?的總結(jié):
-
操作少量的數(shù)據(jù): 適? String
-
單線程操作字符串緩沖區(qū)下操作?量數(shù)據(jù): 適? StringBuilder
-
多線程操作字符串緩沖區(qū)下操作?量數(shù)據(jù): 適? StringBuffer
StringBuffer、StringBuilder和String一樣,也用來代表字符串。String類是不可變類,任何對String的改變都會引發(fā)新的String對象的生成。不同的是StringBuffer 每次都會對 StringBuffer 對象本身進(jìn)?操作,而StringBuffer?成新的對象并改變對象引?。相同情況下使? StringBuilder 相?使? StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的?險。
String、StringBuffer和StringBuilder類都是CharSequence接口的子類
String類通過apend()方法轉(zhuǎn)換成StringBuilder和StringBuffer類。
StringBuffer類和StringBuilder類通過to.String()方法轉(zhuǎn)換成String類型
String 為什么是不可變的?
簡單的來說:String 類中使? final 關(guān)鍵字修飾字符數(shù)組來保存字符串, private final char value[] ,所以 String 對象是不可變的。(在 Java 9 之后,String 類的實(shí)現(xiàn)改? byte 數(shù)組存儲字符串private final byte[] value)
為什么String類被設(shè)計(jì)用final修飾?
- String 類是最常用的類之一,為了效率,禁止被繼承和重寫
- 為了安全。String 類中有很多調(diào)用底層的本地方法,調(diào)用了操作系統(tǒng)的 API,如果方法可以重寫,可能被植入惡意代碼,破壞程序。Java 的安全性也體現(xiàn)在這里。
為了實(shí)現(xiàn)修改字符序列的目的,StringBuffer 和 StringBuilder 底層都是利用可修改的(char,JDK 9 以后是 byte)數(shù)組,二者都繼承了 AbstractStringBuilder,里面包含了基本操作,區(qū)別僅在于最終的方法是否加了 synchronized, StringBuffer 它的線程安全是通過把各種修改數(shù)據(jù)的方法都加上 synchronized 關(guān)鍵字實(shí)現(xiàn)。另外,這個**內(nèi)部數(shù)組應(yīng)該創(chuàng)建成多大的呢?**如果太小,拼接的時候可能要重新創(chuàng)建足夠大的數(shù)組;如果太大,又會浪費(fèi)空間。目前的實(shí)現(xiàn)是,構(gòu)建時初始字符串長度加 16
自動拆箱與裝箱
裝箱:將基本類型?它們對應(yīng)的引?類型包裝起來;
拆箱:將包裝類型轉(zhuǎn)換為基本數(shù)據(jù)類型;
裝箱過程是通過調(diào)用包裝器的valueOf方法(-128,128]實(shí)現(xiàn)的,而拆箱過程是通過調(diào)用包裝器的 xxxValue方法實(shí)現(xiàn)的(xxx代表對應(yīng)的基本數(shù)據(jù)類型)。
裝箱的過程會創(chuàng)建對應(yīng)的對象,這個會消耗內(nèi)存,所以裝箱的過程會增加內(nèi)存的消耗,影響性能
int和Integer區(qū)別,談?wù)処nteger值緩存范圍
int 是我們常說的整形數(shù)字,是 Java 的 8 個原始數(shù)據(jù)類型(Primitive Types,boolean、byte 、short、char、int、float、double、long)之一。
Integer 是 int 對應(yīng)的包裝類,它有一個 int 類型的字段存儲數(shù)據(jù),并且提供了基本操作,比如數(shù)學(xué)運(yùn)算、int 和字符串之間轉(zhuǎn)換等。構(gòu)建 Integer 對象的傳統(tǒng)方式是直接調(diào)用構(gòu)造器,直接 new 一個對象。這個值默認(rèn)緩存是**-128 到 127 之間**
- 基本數(shù)據(jù)類型方便、簡單、高效,但泛型不支持、集合元素不支持
- 不符合面向?qū)ο笏季S
- **包裝類提供很多方法,方便使用,**如 Integer 類 toHexString(int i)、parseInt(String s) 方法等等
我們知道 Java 的對象都是引用類型,如果是一個原始數(shù)據(jù)類型數(shù)組,它在內(nèi)存里是一段連續(xù)的內(nèi)存,而對象數(shù)組則不然,數(shù)據(jù)存儲的是引用,對象往往是分散地存儲在堆的不同位置。這種設(shè)計(jì)雖然帶來了極大靈活性,但是也導(dǎo)致了數(shù)據(jù)操作的低效,尤其是無法充分利用現(xiàn)代 CPU 緩存機(jī)制。Java 為對象內(nèi)建了各種多態(tài)、線程安全等方面的支持。但有些始數(shù)據(jù)類型操作不能保證線程安全如float,double
,繼續(xù)深挖緩存,Integer 的緩存范圍雖然默認(rèn)是 -128 到 127,但是在特別的應(yīng)用場景,比如我們明確知道應(yīng)用會頻繁使用更大的數(shù)值,這時候應(yīng)該怎么辦呢?緩存上限值實(shí)際是可以根據(jù)需要調(diào)整的,JVM 提供了參數(shù)設(shè)置-XX:AutoBoxCacheMax=N
什么是包裝類?為什么要有包裝類?
在一個靜態(tài)方法內(nèi)調(diào)用一個非靜態(tài)成員為什么是非法的?
類的靜態(tài)成員(變量或方法)屬于類本身,在類加載的時候就會分配內(nèi)存,可以通過類名直接訪問
非靜態(tài)成員屬于類的對象,只有在類的對象產(chǎn)生(實(shí)例化)時才會分配內(nèi)存,然后通過類的對象(實(shí)例)去訪問
由于靜態(tài)?法可以不通過對象進(jìn)?調(diào)?,所以,如果一個類的靜態(tài)方法去調(diào)用非靜態(tài)成員的時候,類的非靜態(tài)成員可能不存在,訪問一個內(nèi)存中不存在的東西當(dāng)然會出錯因此在靜態(tài)?法?,不能調(diào)?其他?靜態(tài)變量,也不可以訪問?靜態(tài)變量成員。
在Java中定義一個不做事且沒有參數(shù)的構(gòu)造方法的作用
Java 程序在執(zhí)??類的構(gòu)造?法之前,需要調(diào)用父類的構(gòu)造方法(如果沒有? super() 來調(diào)??類特定的構(gòu)造?法,則會調(diào)??類中“沒有參數(shù)的構(gòu)造?法”)。
因此,如果?類中只定義了有參數(shù)的構(gòu)造?法,?在?類的構(gòu)造?法中?沒有? super() 來調(diào)??類中特定的構(gòu)造?法,因?yàn)?Java 程序在?類中找不到?jīng)]有參數(shù)的構(gòu)造?法可供執(zhí)?,則編譯時發(fā)?錯誤。解決辦法是在?類?加上?個不做事且沒有參數(shù)的構(gòu)造?法以防萬一。
接口和抽象類的區(qū)別
接口:
Java中接口使用interface關(guān)鍵字修飾,接?的?法默認(rèn)是 public ,所有?法在接?中不能有實(shí)現(xiàn)(Java 8 開始接??法可以有默認(rèn)實(shí)現(xiàn))
接口可以包含變量、方法;變量被隱士指定為public static final,方法被隱士指定為public abstract(JDK1.8之前);
接口支持多繼承,一個類可以實(shí)現(xiàn)多個接口
接口沒有構(gòu)造函數(shù)
- 接口中的訪問權(quán)限修飾符只能是 public 或 default
- 接口中的方法必須要實(shí)現(xiàn)類實(shí)現(xiàn),所以不能使用 final
- 接口中所有的方法默認(rèn)都是 abstract,通常 abstract 省略不寫
抽象類:
抽象類使用abstract關(guān)鍵字修飾,被abstract關(guān)鍵字修飾的方法稱為抽象方法,抽象方法只有方法的聲明,沒有方法體
抽象類不能被實(shí)例化,允許被繼承但不允許多繼承(一個類只能繼承一個抽象類,但可以實(shí)現(xiàn)多個接口)
抽象類可以包含屬性、方法、構(gòu)造方法,但是構(gòu)造方法不能用于實(shí)例化,主要用途是被子類調(diào)用。
抽象類可以實(shí)現(xiàn)接口
除了不能被實(shí)例化外,它和普通Java類沒有任何區(qū)別
區(qū)別:
抽象類有構(gòu)造方法,接口無構(gòu)造方法,都不能被實(shí)例化,
抽象類可以有非抽象方法,而接口中的方法都是抽象方法
接口比抽象類速度要慢,因?yàn)樗枰獣r間去尋找在類中實(shí)現(xiàn)的方法
實(shí)現(xiàn)接口的關(guān)鍵字為implements,繼承抽象類的關(guān)鍵字為extends。一個類可以實(shí)現(xiàn)多個接口,但一個類只能繼承一個抽象類
接口成員變量默認(rèn)為public static final,必須賦初值,不能被修改;其所有的成員方法都是public、abstract的。抽象類中成員變量默認(rèn)default,可在子類中被重新定義,也可被重新賦值;抽象方法被abstract修飾,不能被private、static、synchronized和native等修飾,必須以分號結(jié)尾,不帶花括號。
接口只能是功能的定義,而抽象類既可以為功能的定義也可以為功能的實(shí)現(xiàn)。
設(shè)計(jì)層面上的區(qū)別:
抽象類是對一種事物的抽象,即對類抽象,而接口是對行為的抽象。抽象類是對整個類整體進(jìn)行抽象,包括屬性、行為,但是接口卻是對類局部(行為)進(jìn)行抽象。舉個簡單的例子,飛機(jī)和鳥是不同類的事物,但是它們都有一個共性,就是都會飛。那么在設(shè)計(jì)的時候,可以將飛機(jī)設(shè)計(jì)為一個類Airplane,將鳥設(shè)計(jì)為一個類Bird,但是不能將 飛行 這個特性也設(shè)計(jì)為類,因此它只是一個行為特性,并不是對一類事物的抽象描述。此時可以將 飛行 設(shè)計(jì)為一個接口Fly,包含方法fly( ),然后Airplane和Bird分別根據(jù)自己的需要實(shí)現(xiàn)Fly這個接口。然后至于有不同種類的飛機(jī),比如戰(zhàn)斗機(jī)、民用飛機(jī)等直接繼承Airplane即可,對于鳥也是類似的,不同種類的鳥直接繼承Bird類即可。從這里可以看出,繼承是一個 "是不是"的關(guān)系,而 接口 實(shí)現(xiàn)則是 "有沒有"的關(guān)系。如果一個類繼承了某個抽象類,則子類必定是抽象類的種類,而接口實(shí)現(xiàn)則是有沒有、具備不具備的關(guān)系,比如鳥是否能飛(或者是否具備飛行這個特點(diǎn)),能飛行則可以實(shí)現(xiàn)這個接口,不能飛行就不實(shí)現(xiàn)這個接口。
子類初始化的順序
① 父類靜態(tài)代碼塊和靜態(tài)變量。
② 子類靜態(tài)代碼塊和靜態(tài)變量。
③ 父類普通代碼塊和普通變量。
④ 父類構(gòu)造方法。
⑤ 子類普通代碼塊和普通變量。
⑥ 子類構(gòu)造方法。
成員變量與局部變量的區(qū)別有哪些?
-
從語法形式上看:成員變量是在類中定義的,?局部變量是在?法中定義的或是?法的參數(shù);成員變量可以被 public , private , static 等修飾符所修飾,?局部變量不能被訪問控制修飾符及 static 所修飾;但是,成員變量和局部變量都能被 final 所修飾。
-
從變量在內(nèi)存中的存儲?式來看:成員變量是對象的一部分,對象存于堆內(nèi)存;如果局部變量類型為基本數(shù)據(jù)類型,那么存儲在棧內(nèi)存,如果為引?數(shù)據(jù)類型,那存放的是指向堆內(nèi)存對象的引?或者是指向常量池中的地址。
-
從變量在內(nèi)存中的?存時間上看:成員變量是對象的?部分,它隨著對象的創(chuàng)建?存在,?局部變量隨著?法的調(diào)???動消失。
-
成員變量如果沒有被賦初值:則會?動以類型的默認(rèn)值?賦值(?種情況例外:被 final 修飾的成員變量也必須顯式地賦值),?局部變量則不會?動賦值。
創(chuàng)建一個對象用什么運(yùn)算符?對象實(shí)例與對象引用有何不同?
new運(yùn)算符
new 創(chuàng)建對象實(shí)例(對象實(shí)例在堆內(nèi)存中),對象引?指向?qū)ο髮?shí)例(對象引?存放在棧內(nèi)存中)。?個對象引?可以指向 0 個或 1 個對象(?根繩?可以不系?球,也可以系?個?球);?個對象可以有 n 個引?指向它(可以? n 條繩?系住?個?球)
什么是方法的返回值?返回值在類的方法里有什么作用?
?法的返回值是指我們獲取到的某個?法體中的代碼執(zhí)?后產(chǎn)?的結(jié)果!
返回值的作?:接收出結(jié)果,使得它可以?于其他的操作
?個類的構(gòu)造?法的作?是什么? 若?個類沒有聲明構(gòu)造?法,該程序能正確執(zhí)?嗎? 為什么?
主要作?是完成對類對象的初始化?作。
可以執(zhí)?,因?yàn)?個類即使沒有聲明構(gòu)造?法也會有默認(rèn)的不帶參數(shù)的構(gòu)造?法
構(gòu)造方法有哪些特性
- 名字與類名相同。
- 構(gòu)造方法無返回值類型(void也不行)
- ?成類的對象時?動執(zhí)?,?需調(diào)?
- 構(gòu)造方法不能被繼承
- 構(gòu)造方法可以沒有(默認(rèn)一個無參構(gòu)造方法),也可以有多個構(gòu)造方法。他們之間構(gòu)成重載關(guān)系
- 構(gòu)造方法可以重載,不可重寫
作用:
(1)初始化對象,為對象賦初值。
(2)簡化我們?yōu)轭愖侄钨x值的代碼。
靜態(tài)方法和實(shí)例方法有何不同
-
在外部調(diào)?靜態(tài)?法時,可以使?"類名.?法名"的?式,也可以使?"對象名.?法名"的?式。?實(shí)例?法只有后?這種?式。也就是說,調(diào)?靜態(tài)?法可以?需創(chuàng)建對象。
-
靜態(tài)?法在訪問本類的成員時,只允許訪問靜態(tài)成員(即靜態(tài)成員變量和靜態(tài)?法),?不允許訪問實(shí)例成員變量和實(shí)例?法;實(shí)例?法則?此限制。
對象的相等和指向它們的應(yīng)用相等,兩者有什么不同?
對象的相等,?的是內(nèi)存中存放的內(nèi)容是否相等。
?引?相等,?的是他們指向的內(nèi)存地址是否相等
在調(diào)用子類構(gòu)造方法之前會先調(diào)用父類沒有參數(shù)的構(gòu)造方法,其目的是?
幫助?類做初始化?作
在初始化子類的時候,一定要使父類已經(jīng)存在了(所以要先初始化父類對象,即要調(diào)用沒有參數(shù)的構(gòu)造方法來初始化對象).不然沒辦法調(diào)用父類的構(gòu)造函數(shù).父類必須在子類初始化之前就已經(jīng)準(zhǔn)備好.
Object類有哪些方法?
equals:檢測對象是否相等,默認(rèn)使用 == 比較對象引用,可以重寫 equals 方法自定義比較規(guī)則。equals 方法規(guī)范:自反性、對稱性、傳遞性、一致性、對于任何非空引用 x,x.equals(null) 返回 false。
hashCode:散列碼是由對象導(dǎo)出的一個整型值,沒有規(guī)律,每個對象都有默認(rèn)散列碼,值由對象存儲地址得出。字符串散列碼由內(nèi)容導(dǎo)出,值可能相同。為了在集合中正確使用,一般需要同時重寫 equals 和 hashCode,要求 equals 相同 hashCode 必須相同,hashCode 相同 equals 未必相同,因此 hashCode 是對象相等的必要不充分條件。
toString:打印對象時默認(rèn)的方法,如果沒有重寫打印的是表示對象值的一個字符串。
clone:clone 方法聲明為 protected,類只能通過該方法克隆它自己的對象,如果希望其他類也能調(diào)用該方法必須定義該方法為 public。如果一個對象的類沒有實(shí)現(xiàn) Cloneable 接口,該對象調(diào)用 clone 方拋出一個 CloneNotSupport 異常。默認(rèn)的 clone 方法是淺拷貝,一般重寫 clone 方法需要實(shí)現(xiàn) Cloneable 接口并指定訪問修飾符為 public。
finalize:確定一個對象死亡至少要經(jīng)過兩次標(biāo)記,如果對象在可達(dá)性分析后發(fā)現(xiàn)沒有與 GC Roots 連接的引用鏈會被第一次標(biāo)記,隨后進(jìn)行一次篩選,條件是對象是否有必要執(zhí)行 finalize 方法。假如對象沒有重寫該方法或方法已被虛擬機(jī)調(diào)用,都視為沒有必要執(zhí)行。如果有必要執(zhí)行,對象會被放置在 F-Queue 隊(duì)列,由一條低調(diào)度優(yōu)先級的 Finalizer 線程去執(zhí)行。虛擬機(jī)會觸發(fā)該方法但不保證會結(jié)束,這是為了防止某個對象的 finalize 方法執(zhí)行緩慢或發(fā)生死循環(huán)。只要對象在 finalize 方法中重新與引用鏈上的對象建立關(guān)聯(lián)就會在第二次標(biāo)記時被移出回收集合。由于運(yùn)行代價高昂且無法保證調(diào)用順序,在 JDK 9 被標(biāo)記為過時方法,并不適合釋放資源。
getClass:返回包含對象信息的類對象。
wait / notify / notifyAll:阻塞或喚醒持有該對象鎖的線程。
==與equals區(qū)別(重要)
== : 它的作?是判斷兩個對象的地址是不是相等。即,判斷兩個對象是不是同?個對象(基本數(shù)據(jù)類型?較的是值,引?數(shù)據(jù)類型?較的是內(nèi)存地址)。
equals() : 它的作?也是判斷兩個對象是否相等。但它?般有兩種使?情況:
情況 1:類沒有覆蓋 equals() ?法。則通過 equals() ?較該類的兩個對象時,等價于通過“==”?較這兩個對象。
情況 2:類覆蓋了 equals() ?法。?般,我們都覆蓋 equals() ?法來?較兩個對象的內(nèi)容是否相等;若它們的內(nèi)容相等,則返回 true (即,認(rèn)為這兩個對象相等)
說明:
String 中的 equals ?法是被重寫過的,因?yàn)?object 的 equals ?法是??的對象的內(nèi)存地址,? String 的 equals ?法??的是對象的值。
當(dāng)創(chuàng)建 String 類型的對象時,虛擬機(jī)會在常量池中查找有沒有已經(jīng)存在的值和要創(chuàng)建的值相同的對象,如果有就把它賦給當(dāng)前引?。如果沒有就在常量池中重新創(chuàng)建?個 String 對象。
hashCode與equals區(qū)別(重要)
hashCode()介紹:
hashCode() 的作?是獲取哈希碼,也稱為散列碼;它實(shí)際上是返回?個 int 整數(shù)。這個哈希碼的作?是確定該對象在哈希表中的索引位置。
hashCode() 定義在 JDK 的 Object 類中,這就意味著 Java 中的任何類都包含有 hashCode() 函數(shù)。另外需要注意的是: Object 的 hashcode ?法是本地?法,也就是? c 語?或 c++ 實(shí)現(xiàn)的,該?法通常?來將對象的 內(nèi)存地址 轉(zhuǎn)換為整數(shù)之后返回。
散列表存儲的是鍵值對(key-value),它的特點(diǎn)是:能根據(jù)“鍵”快速的檢索出對應(yīng)的“值”。這其中就利?到了散列碼!(可以快速找到所需要的對象)
為什么要有hashCode:
當(dāng)你把對象加? HashSet 時, HashSet 會先計(jì)算對象的 hashcode 值來判斷對象加?的位置,同時也會與其他已經(jīng)加?的對象的 hashcode 值作?較,如果沒有相符的 hashcode, HashSet會假設(shè)對象沒有重復(fù)出現(xiàn)。但是如果發(fā)現(xiàn)有相同 hashcode 值的對象,這時會調(diào)? equals() ?法來檢查 hashcode 相等的對象是否真的相同。如果兩者相同, HashSet 就不會讓其加?操作成功。如果不同的話,就會重新散列到其他位置。這樣我們就??減少了 equals 的次數(shù),相應(yīng)就??提?了執(zhí)?速度。
為什么重寫equals 時必須重寫 hashCode?法:
如果兩個對象相等,則 hashcode ?定也是相同的。兩個對象相等,對兩個對象分別調(diào)? equals?法都返回 true。但是,兩個對象有相同的 hashcode 值,這兩個對象不?定是相等的 。因此,equals?法被覆蓋過,則 hashCode ?法也必須被覆蓋。
為什么兩個對象有相同的hashcode值,它們也不?定是相等的:
因?yàn)?hashCode() 所使?的雜湊算法也許剛好會讓多個對象傳回相同的雜湊值。越糟糕的雜湊算法越容易碰撞,但這也與數(shù)據(jù)值域分布的特性有關(guān)(所謂碰撞也就是指的是不同的對象得到相同的 hashCode 。我們剛剛也提到了 HashSet ,如果 HashSet 在對?的時候,同樣的 hashcode 有多個對象,它會使? equals() 來判斷是否真的相同。也就是說 hashcode 只是?來縮?查找成本。
訪問權(quán)限控制符有哪些?
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-dnV1eniR-1632494423973)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210909131559139.png)]
-
private:表示私有的,作用范圍是當(dāng)前類(類可見性)。
-
default:表示沒有修飾符修飾,作用范圍是當(dāng)前類+當(dāng)前包(包可見型)。
-
protected:表示受保護(hù)的,作用范圍是當(dāng)前類+當(dāng)前包+包外的子類(子類可見性)。
-
public:表示公開的,作用范圍是是當(dāng)前類+當(dāng)前包+其它包(項(xiàng)目可見性)。
訪問權(quán)限控制符不能修飾局部變量
為什么Java中只有值傳遞?
Java程序設(shè)計(jì)語?總是采?按值調(diào)?。也就是說,?法得到的是所有參數(shù)值的?個拷?,也就是說,?法不能修改傳遞給它的任何參數(shù)變量的內(nèi)容。
簡述線程,程序,進(jìn)程的基本概念,以及他們之間關(guān)系是什么?
進(jìn)程:
-
程序由指令和數(shù)據(jù)組成,但這些指令要運(yùn)行,數(shù)據(jù)要讀寫,就必須將指令加載至CPU,數(shù)據(jù)加載至內(nèi)存,在指令進(jìn)行運(yùn)行過程中還需要用到磁盤,網(wǎng)絡(luò)等設(shè)備。進(jìn)程就是用來加載指令,管理內(nèi)存,管理IO的
-
當(dāng)一個程序被運(yùn)行,從磁盤加載這個程序的代碼至內(nèi)存,這時就開啟了一個進(jìn)程
進(jìn)程是程序的?次執(zhí)?過程,是系統(tǒng)運(yùn)?程序的基本單位,因此進(jìn)程是動態(tài)的。系統(tǒng)運(yùn)??個程序即是?個進(jìn)程從創(chuàng)建,運(yùn)?到消亡的過程。簡單來說,?個進(jìn)程就是?個執(zhí)?中的程序,它在計(jì)算機(jī)中?個指令接著?個指令地執(zhí)?著,同時,每個進(jìn)程還占有某些系統(tǒng)資源如 CPU 時間,內(nèi)存空間,?件,輸?輸出設(shè)備的使?權(quán)等等。換句話說,當(dāng)程序在執(zhí)?時,將會被操作系統(tǒng)載?內(nèi)存中。
線程:
- 一個進(jìn)程可以分為一到多個線程
- 一個線程就是一個指令流,將指令流中的一條條指令以一定的順序交給CPU執(zhí)行
- Java中,線程作為最小調(diào)度單位,進(jìn)程作為資源分配的最小單位,在windows中進(jìn)程是不活動的,只是作為線程的容器
二者對比:
- 進(jìn)程基本上是相互獨(dú)立的,而線程存在于進(jìn)程內(nèi),是進(jìn)程的一個子集
- 進(jìn)程擁有共享的資源,如內(nèi)存空間等,供其內(nèi)部的線程共享
- 與進(jìn)程不同的是同類的多個線程共享同?塊內(nèi)存空間和?組系統(tǒng)資源,所以系統(tǒng)在產(chǎn)??個線程,或是在各個線程之間作切換?作時,負(fù)擔(dān)要?進(jìn)程?得多,也正因?yàn)槿绱?#xff0c;線程也被稱為輕量級進(jìn)程
- 進(jìn)程間通信較為復(fù)雜
? 同一臺計(jì)算機(jī)的進(jìn)程通信稱為IPC
? 不同計(jì)算機(jī)之間的進(jìn)程通信,需要通過網(wǎng)絡(luò),并遵守共同的協(xié)議,例如HTTP
- 線程通信相對簡單,因?yàn)樗麄児蚕磉M(jìn)程內(nèi)的內(nèi)存,一個例子是多個線程可以訪問同一個共享變量
- 線程更輕量,線程上下文切換成本一般要比進(jìn)程上下文低
線程有哪些基本狀態(tài)
Java 線程在運(yùn)?的?命周期中的指定時刻只可能處于下? 6 種狀態(tài)的其中?個狀態(tài):
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-qleWUhTu-1632494423975)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901090110364.png)]
線程創(chuàng)建之后它將處于 NEW(新建) 狀態(tài),調(diào)? start() ?法后開始運(yùn)?,線程這時候處于READY(可運(yùn)?)狀態(tài)。可運(yùn)?狀態(tài)的線程獲得了 cpu 時間?(timeslice)后就處于RUNNING(運(yùn)?) 狀態(tài)。
當(dāng)線程執(zhí)? wait() ?法之后,線程進(jìn)? WAITING**(等待)狀態(tài)。進(jìn)?等待狀態(tài)的線程需要依靠其他線程的通知才能夠返回到運(yùn)?狀態(tài),? TIME_WAITING(超時等待) 狀態(tài)相當(dāng)于在等待狀態(tài)的基礎(chǔ)上增加了超時限制,?如通過 sleep(long millis) ?法或 wait(long millis) ?法可以將Java 線程置于 TIMED WAITING 狀態(tài)。當(dāng)超時時間到達(dá)后 Java 線程將會返回到 RUNNABLE 狀態(tài)。
當(dāng)線程調(diào)?同步?法時,在沒有獲取到鎖的情況下,線程將會進(jìn)?BLOCKED(阻塞)狀態(tài)。線程在執(zhí)? Runnable 的 run() ?法之后將會進(jìn)?到 TERMINATED(終?) 狀態(tài)。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-9XW2O2TL-1632494423978)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901090757562.png)]
final關(guān)鍵字
-
當(dāng)? final 修飾?個類時,表明這個類不能被繼承。final 類中的所有成員?法都會被隱式地指定為 final ?法。
-
使? final ?法的原因有兩個。第?個原因是把?法鎖定,以防任何繼承類修改它的含義;第?個原因是效率。在早期的 Java 實(shí)現(xiàn)版本中,會將 final ?法轉(zhuǎn)為內(nèi)嵌調(diào)?。但是如果?法過于龐?,可能看不到內(nèi)嵌調(diào)?帶來的任何性能提升(現(xiàn)在的 Java 版本已經(jīng)不需要使?final ?法進(jìn)?這些優(yōu)化了)。類中所有的 private ?法都隱式地指定為 final。
-
修飾變量是final用得最多的地方,對于一個final變量,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始化之后便不能更改;如果是引用類型的變量,則在對其初始化之后便不能再讓其指向另一個對象。但是它指向的對象的內(nèi)容是可變的。
.類的final變量和普通變量有什么區(qū)別?
當(dāng)用final作用于類的成員變量時,成員變量必須在定義時或者構(gòu)造器中進(jìn)行初始化賦值,而且final變量一旦被初始化賦值之后,就不能再被賦值了。
我們可以將方法或者類聲明為 final,這樣就可以明確告知別人,這些行為是不許修改的。如果你關(guān)注過 Java 核心類庫的定義或源碼, 有沒有發(fā)現(xiàn) java.lang 包下面的很多類,相當(dāng)一部分都被聲明成為 final class?在第三方類庫的一些基礎(chǔ)類中同樣如此,這可以有效避免API 使用者更改基礎(chǔ)功能,某種程度上,這是保證平臺安全的必要手段。使用 final 修飾參數(shù)或者變量,也可以清楚地避免意外賦值導(dǎo)致的編程錯誤,甚至,有人明確推薦將所有方法參數(shù)、本地變量、成員變量聲明成 final。final 變量產(chǎn)生了某種程度的不可變(immutable)的效果,所以,可以用于保護(hù)只讀數(shù)據(jù),尤其是在并發(fā)編程中,因?yàn)槊鞔_地不能再賦值 final 變量,有利于減少額外的同步開銷,也可以省去一些防御性拷貝的必要。final 也許會有性能的好處,很多文章或者書籍中都介紹了可在特定場景提高性能,比如,利用 final 可能有助于 JVM 將方法進(jìn)行內(nèi)聯(lián),可以改善編譯器進(jìn)行條件編譯的能力等等。坦白說,很多類似的結(jié)論都是基于假設(shè)得出的,比如現(xiàn)代高性能 JVM(如 HotSpot)判斷內(nèi)聯(lián)未必依賴 final 的提示,要相信 JVM 還是非常智能的。類似的,final 字段對性能的影響,大部分情況下,并沒有考慮的必要。
public class Test {public static void main(String[] args) {String a = "hello2"; final String b = "hello";String d = "hello";String c = b + 2; String e = d + 2;System.out.println((a == c));//trueSystem.out.println((a == e));//false}
}
final與static的區(qū)別?
java中的異常處理
體檢java平臺設(shè)計(jì)者對不同異常的分類。
在 Java 中,所有的異常都有?個共同的祖先 java.lang 包中的 Throwable 類。 Throwable 類有兩個重要的?類 Exception (異常)和 Error (錯誤)。 Exception 能被程序本身處理( try_catch ), Error 是?法處理的(只能盡量避免)。
Exception 和 Error ?者都是 Java 異常處理的重要?類,各?都包含?量?類。
Exception:程序本身可以處理的異常,是程序運(yùn)行過程中常見的可以預(yù)料的情況,可以通過 catch 來進(jìn)?捕獲并進(jìn)行相應(yīng)的處理。 Exception ?可以分為 受檢查異常(必須處理) 和 不受檢查異常(可以不處理)。
- 受檢查異常:Java 代碼在編譯過程中,如果受檢查異常沒有被 catch / throw 處理的話,就沒辦法通過編譯,Exception 類及其?類都屬于檢查異常;常?的受檢查異常有: IO 相關(guān)的異常、 ClassNotFoundException 、 SQLException …
- 不受檢查異常(就是所謂的運(yùn)行時異常):Java 代碼在編譯過程中 ,我們即使不處理不受檢查異常也可以正常通過編譯。RuntimeException 及其?類都統(tǒng)稱為?受檢查異常,例如: NullPointExecrption 、 NumberFormatException (字符串轉(zhuǎn)換為數(shù)字)、 ArrayIndexOutOfBoundsException (數(shù)組越界)、 ClassCastException (類型轉(zhuǎn)換錯誤)、 ArithmeticException (算術(shù)錯誤)等。
Error : **Error 屬于程序?法處理的錯誤 ,是正常情況下不太可能出現(xiàn)的情況。**我們沒辦法通過 catch 來進(jìn)?捕獲 。例如,Java 虛擬機(jī)運(yùn)?錯誤( Virtual MachineError )、虛擬機(jī)內(nèi)存不夠錯誤( OutOfMemoryError )、類定義錯誤( NoClassDefFoundError )等 。這些異常發(fā)?時,Java虛擬機(jī)(JVM)?般會選擇線程終?。受檢查異常
- 捕獲異常后,不要生吞(swallow)異常。這是異常處理中要特別注意的事情,因?yàn)楹芸赡軙?dǎo)致非常難以診斷的詭異情況。生吞異常,往往是基于假設(shè)這段代碼可能不會發(fā)生,或者感覺忽略異常是無所謂的,但是千萬不要在產(chǎn)品代碼做這種假設(shè)!如果我們不把異常拋出來,或者也沒有輸出到日志(Logger)之類,程序可能在后續(xù)代碼以不可控的方式結(jié)束。沒人能夠輕易判斷究竟是哪里拋出了異常,以及是什么原因產(chǎn)生了異常
- 有的時候,我們會根據(jù)需要自定義異常。一個重要考量就是信息安全。比如,用戶數(shù)據(jù)一般是不可以輸出到日志里面的
- 我們從性能角度來審視一下 Java 的異常處理機(jī)制,這里有兩個可能會相對昂貴的地方。try-catch 代碼段會產(chǎn)生額外的性能開銷,或者換個角度說,它往往會影響 JVM 對代碼進(jìn)行優(yōu)化,所以建議僅捕獲有必要的代碼段,盡量不要一個大的 try 包住整段的代碼。Java 每實(shí)例化一個 Exception,都會對當(dāng)時的棧進(jìn)行快照,這是一個相對比較重的操作。如果發(fā)生的非常頻繁,這個開銷可就不能被忽略了。當(dāng)我們的服務(wù)出現(xiàn)反應(yīng)變慢、吞吐量下降的時候,檢查發(fā)生最頻繁的 Exception 也是一種思路。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-2TowOvjc-1632494423980)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901093446188.png)]
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-DBkS73Qc-1632494423983)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901093500668.png)]
Throwable類常用方法:
public string getMessage() :返回異常發(fā)?時的簡要描述
public string toString() :返回異常發(fā)?時的詳細(xì)信息
public string getLocalizedMessage() :返回異常對象的本地化信息。使?Throwable 的?類覆蓋這個?法,可以?成本地化信息。如果?類沒有覆蓋該?法,則該?法返回的信息與getMessage() 返回的結(jié)果相同
public void printStackTrace() :在控制臺上打印 Throwable 對象封裝的異常信息
異常處理總結(jié):
try塊: ?于捕獲異常。其后可接零個或多個 catch 塊,如果沒有 catch 塊,則必須跟?個 finally 塊。
catch 塊: ?于處理 try 捕獲到的異常。
finally 塊: ?論是否捕獲或處理異常, finally 塊?的語句都會被執(zhí)?。當(dāng)在 try 塊或
catch 塊中遇到 return 語句時, finally 語句塊將在?法返回之前被執(zhí)?。當(dāng) try 語句和 finally 語句中都有 return 語句時,在?法返回之前,finally 語句的內(nèi)容將被執(zhí)?,并且 finally 語句的返回值將會覆蓋原始的返回值
在以下 3 種特殊情況下, finally 塊不會被執(zhí)?:
-
在 try 或 finally 塊中?了 System.exit(int) 退出程序。但是,如果 System.exit(int) 在異常語句之后, finally 還是會被執(zhí)?
-
程序所在的線程死亡。
-
關(guān)閉 CPU。
java序列化中如果有些字段不想進(jìn)行序列化怎么辦?
java序列化:即寫文件,將對象轉(zhuǎn)化為字節(jié)序列方便存儲在文件中
java反序列化:即讀文件,將字節(jié)序列轉(zhuǎn)化為對象
對于不想進(jìn)?序列化的變量,使? transient 關(guān)鍵字修飾。transient 關(guān)鍵字的作?是:阻?實(shí)例中那些?此關(guān)鍵字修飾的的變量序列化;當(dāng)對象被反序列化時,被 transient 修飾的變量值不會被持久化和恢復(fù)。transient 只能修飾變量,不能修飾類和?法。
獲取用鍵盤輸入的兩種常用方法
通過Scanner:
Scanner input = new Scanner(System.in);
String s = input.nextLine();
input.close();
通過BufferedReader:
Scanner input = new Scanner(System.in);
String s = input.nextLine();
input.close();
java中的IO流
IO流:數(shù)據(jù)傳輸是需要通道的,而IO流就是數(shù)據(jù)傳輸?shù)耐ǖ馈O流可以形象的比喻為運(yùn)送貨物的傳輸帶。
java中的IO流分為幾種
- 按照流的流向分,可以分為輸?流和輸出流;
- 按照操作單元劃分,可以劃分為字節(jié)流和字符流;
- 按照流的??劃分為節(jié)點(diǎn)流和處理流。
InputStream/Reader: 所有的輸?流的基類,前者是字節(jié)輸?流,后者是字符輸?流。
OutputStream/Writer: 所有輸出流的基類,前者是字節(jié)輸出流,后者是字符輸出流。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-TYgB12wq-1632494423986)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901104125545.png)]
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-gBiCQC4i-1632494423988)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901103711639.png)]
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-1PoZeikQ-1632494423990)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901101837461.png)]
有字節(jié)流為什么還要有字符流
問題本質(zhì)想問:不管是?件讀寫還是?絡(luò)發(fā)送接收,信息的最?存儲單元都是字節(jié),那為什么****I/O 流操作要分為字節(jié)流操作和字符流操作呢?
回答:字符流是由 Java 虛擬機(jī)將字節(jié)轉(zhuǎn)換得到的,問題就出在這個過程?常耗時,并且,如果我們不知道編碼類型就很容易出現(xiàn)亂碼問題。所以, I/O 流就?脆提供了?個直接操作字符的接?,?便我們平時對字符進(jìn)?流操作。如果?頻?件、圖?等媒體?件?字節(jié)流?較好,如果涉及到字符的話使?字符流?較好。
BIO,NIO和AIO區(qū)別
BIO (Blocking I/O): 同步阻塞 I/O 模式,數(shù)據(jù)的讀取寫?必須阻塞在?個線程內(nèi)等待其完成。在活動連接數(shù)不是特別?(?于單機(jī) 1000)的情況下,這種模型是?較不錯的,可以讓每?個連接專注于??的 I/O 并且編程模型簡單,也不?過多考慮系統(tǒng)的過載、限流等問題。但是,當(dāng)?對?萬甚?百萬級連接的時候,傳統(tǒng)的 BIO 模型是?能為?的。
我們建立網(wǎng)絡(luò)連接的時候采用BIO模式,需要先在服務(wù)端啟動一個ServerSocket,然后在客戶端啟動Socket來對服務(wù)端進(jìn)行通信,默認(rèn)情況下服務(wù)端需要對每個請求建立一堆線程等待請求,而客戶端發(fā)送請求后,先咨詢服務(wù)端是否有線程相應(yīng),如果沒有則會一直等待或者遭到拒絕請求,如果有的話,客戶端會線程會等待請求結(jié)束后才繼續(xù)執(zhí)行。
NIO (Non-blocking/New I/O): 同步?阻塞的 I/O 模型,NIO 提供?持阻塞和?阻塞兩種模式。阻塞模式使?就像傳統(tǒng)中的?持?樣,?較簡單,但是性能和可靠性都不好;?阻塞模式對于?負(fù)載、?并發(fā)的(?絡(luò))應(yīng)?,應(yīng)使? NIO 的?阻塞模式來開發(fā)
NIO本身是基于事件驅(qū)動思想來完成的,其主要想解決的是BIO的大并發(fā)問題: 在使用同步I/O的網(wǎng)絡(luò)應(yīng)用中,如果要同時處理多個客戶端請求,或是在客戶端要同時和多個服務(wù)器進(jìn)行通訊,就必須使用多線程來處理。也就是說,將每一個客戶端請求分配給一個線程來單獨(dú)處理。這樣做雖然可以達(dá)到我們的要求,但同時又會帶來另外一個問題。由于每創(chuàng)建一個線程,就要為這個線程分配一定的內(nèi)存空間(也叫工作存儲器),而且操作系統(tǒng)本身也對線程的總數(shù)有一定的限制。如果客戶端的請求過多,服務(wù)端程序可能會因?yàn)椴豢爸刎?fù)而拒絕客戶端的請求,甚至服務(wù)器可能會因此而癱瘓。使用BIO的時候往往會引入多線程,每個連接一個單獨(dú)的線程,實(shí)現(xiàn)異步處理,降低服務(wù)器壓力
AIO (Asynchronous I/O): (即 NIO 2)異步?阻塞的 IO 模型。AIO 是異步 IO 的縮寫,雖然 NIO 在?絡(luò)操作中,提供了?阻塞的?法,但是 NIO 的 IO ?為還是同步的。對于 NIO 來說,我們的業(yè)務(wù)線程是在 IO 操作準(zhǔn)備好時,得到通知,接著就由這個線程??進(jìn)? IO 操作,IO 操作本身是同步的。查閱?上相關(guān)資料,我發(fā)現(xiàn)就?前來說 AIO 的應(yīng)?還不是很?泛。
以銀行取款為例:
- 同步 : 自己親自出馬持銀行卡到銀行取錢(使用同步IO時,Java自己處理IO讀寫);
- 異步 : 委托一小弟拿銀行卡到銀行取錢,然后給你(使用異步IO時,Java將IO讀寫委托給OS處理,需要將數(shù)據(jù)緩沖區(qū)地址和大小傳給OS(銀行卡和密碼),OS需要支持異步IO操作API);
- 阻塞 : ATM排隊(duì)取款,你只能等待(使用阻塞IO時,Java調(diào)用會一直阻塞到讀寫完成才返回);
- 非阻塞 : 柜臺取款,取個號,然后坐在椅子上做其它事,等號廣播會通知你辦理,沒到號你就不能去,你可以不斷問大堂經(jīng)理排到了沒有,大堂經(jīng)理如果說還沒到你就不能去(使用非阻塞IO時,如果不能讀寫Java調(diào)用會馬上返回,當(dāng)IO事件分發(fā)器會通知可讀寫時再繼續(xù)進(jìn)行讀寫,不斷循環(huán)直到讀寫完成)
Java對BIO、NIO、AIO的支持:
- Java BIO : 同步并阻塞,服務(wù)器實(shí)現(xiàn)模式為一個連接一個線程,即客戶端有連接請求時服務(wù)器端就需要啟動一個線程進(jìn)行處理,如果這個連接不做任何事情會造成不必要的線程開銷,當(dāng)然可以通過線程池機(jī)制改善。
- Java NIO : 同步非阻塞,服務(wù)器實(shí)現(xiàn)模式為一個請求一個線程,即客戶端發(fā)送的連接請求都會注冊到多路復(fù)用器上,多路復(fù)用器輪詢到連接有I/O請求時才啟動一個線程進(jìn)行處理。
- Java AIO(NIO.2) : 異步非阻塞,服務(wù)器實(shí)現(xiàn)模式為一個有效請求一個線程,客戶端的I/O請求都是由OS先完成了再通知服務(wù)器應(yīng)用去啟動線程進(jìn)行處理,
BIO、NIO、AIO適用場景分析:
- BIO方式適用于連接數(shù)目比較小且固定的架構(gòu),這種方式對服務(wù)器資源要求比較高,并發(fā)局限于應(yīng)用中,JDK1.4以前的唯一選擇,但程序直觀簡單易理解。
- NIO方式適用于連接數(shù)目多且連接比較短(輕操作)的架構(gòu),比如聊天服務(wù)器,并發(fā)局限于應(yīng)用中,編程比較復(fù)雜,JDK1.4開始支持。
- AIO方式使用于連接數(shù)目多且連接比較長(重操作)的架構(gòu),比如相冊服務(wù)器,充分調(diào)用OS參與并發(fā)操作,編程比較復(fù)雜,JDK7開始支持。
深拷貝和淺拷貝
-
淺拷?:對基本數(shù)據(jù)類型進(jìn)?值傳遞,對引?數(shù)據(jù)類型進(jìn)?引?傳遞般的拷?,此為淺拷?。
-
深拷?:對基本數(shù)據(jù)類型進(jìn)?值傳遞,對引?數(shù)據(jù)類型,創(chuàng)建?個新的對象,并復(fù)制其內(nèi)容,此為深拷?。
深拷貝和淺拷貝最根本的區(qū)別在于是否真正獲取一個對象的復(fù)制實(shí)體,而不是引用。
- 假設(shè)B復(fù)制了A,修改A的時候,看B是否發(fā)生變化:
- 如果B跟著也變了,說明是淺拷貝,拿人手短!(修改堆內(nèi)存中的同一個值)
- 如果B沒有改變,說明是深拷貝,自食其力!(修改堆內(nèi)存中的不同的值)
淺復(fù)制:僅僅是指向被復(fù)制的內(nèi)存地址,如果原地址發(fā)生改變,那么淺復(fù)制出來的對象也會相應(yīng)的改變。
深復(fù)制:在計(jì)算機(jī)中開辟一塊新的內(nèi)存地址用于存放復(fù)制的對象。
內(nèi)存泄漏和內(nèi)存溢出的區(qū)別
- 內(nèi)存溢出(out of memory):指程序在申請內(nèi)存時,沒有足夠的內(nèi)存空間供其使用,出現(xiàn) out of memory。
- 內(nèi)存泄露(memory leak):指程序在申請內(nèi)存后,無法釋放已申請的內(nèi)存空間,內(nèi)存泄露堆積會導(dǎo)致內(nèi)存被占光。
- memory leak 最終會導(dǎo)致 out of memory。
java的垃圾回收機(jī)制
垃圾回收機(jī)制,簡稱 GC
- Java 語言不需要程序員直接控制內(nèi)存回收,由 JVM 在后臺自動回收不再使用的內(nèi)存
- 提高編程效率
- 保護(hù)程序的完整性
特點(diǎn)
- 回收 JVM 堆內(nèi)存里的對象空間,不負(fù)責(zé)回收棧內(nèi)存數(shù)據(jù)
- 垃圾回收發(fā)生具有不可預(yù)知性,程序無法精確控制垃圾回收機(jī)制執(zhí)行
- 可以將對象的引用變量設(shè)置為 null,垃圾回收機(jī)制可以在下次執(zhí)行時回收該對象。
- 垃圾回收機(jī)制回收任何對象之前,會先調(diào)用對象的 finalize() 方法。
- 可以通過 System.gc() 或 Runtime.getRuntime().gc() 通知系統(tǒng)進(jìn)行垃圾回收,會有一些效果,但系統(tǒng)是否進(jìn)行垃圾回收依然不確定
java.sql.Date和java.util.Date的區(qū)別
- java.sql.Date 是 java.util.Date 的子類
- java.util.Date 是 JDK 中的日期類,精確到時、分、秒、毫秒
- java.sql.Date 與數(shù)據(jù)庫 Date 相對應(yīng)的一個類型,只有日期部分,時分秒都會設(shè)置為 0,如:2019-10-23 00:00:00
&和&&的作用和區(qū)別
&:
- 邏輯與,& 兩邊的表達(dá)式都會進(jìn)行運(yùn)算
- 整數(shù)的位運(yùn)算符
&&:
- 短路與,&& 左邊的表達(dá)式結(jié)果為 false 時,&& 右邊的表達(dá)式不參與計(jì)算
Java中有幾種基本數(shù)據(jù)類型?它們分別占多大字節(jié)?
- byte:1個字節(jié),8位
- short:2個字節(jié),16位
- int:4個字節(jié),32位
- long:8個字節(jié),64位
- float:4個字節(jié),32位
- double:8個字節(jié),64位
- boolean:官方文檔未明確定義,依賴于 JVM 廠商的具體實(shí)現(xiàn)。邏輯上理解是占用 1位,但是實(shí)際中會考慮計(jì)算機(jī)高效存儲因素
- char:2個字節(jié),16位
補(bǔ)充說明:字節(jié)的英文是 byte,位的英文是 bit
什么是java序列化?什么情況下需要序列化?
序列化:將 Java 對象轉(zhuǎn)換成字節(jié)流的過程。(寫文件)
反序列化:將字節(jié)流轉(zhuǎn)換成 Java 對象的過程。(讀文件)
當(dāng) Java 對象需要在網(wǎng)絡(luò)上傳輸 或者 持久化存儲到文件中時,就需要對 Java 對象進(jìn)行序列化處理。
序列化的實(shí)現(xiàn):類實(shí)現(xiàn) Serializable 接口,這個接口沒有需要實(shí)現(xiàn)的方法。實(shí)現(xiàn) Serializable 接口是為了告訴 jvm 這個類的對象可以被序列化。
注意事項(xiàng):
- 某個類可以被序列化,則其子類也可以被序列化
- 對象中的某個屬性是對象類型,需要序列化也必須實(shí)現(xiàn) Serializable 接口
- 聲明為 static 和 transient 的成員變量,不能被序列化。static 成員變量是描述類級別的屬性,transient 表示臨時數(shù)據(jù)
- 反序列化讀取序列化對象的順序要保持一致
throw和throws區(qū)別
throws是用來聲明一個方法可能拋出的所有異常信息,throws是將異常聲明但是不處理,而是將異常往上傳,誰調(diào)用我就交給誰處理。
而throw則是指拋出的一個具體的異常類型。
什么是hash和hash表?
Hash,是把任意長度的輸入通過散列算法變換成固定長度的輸出,該輸出就是散列值。使用Hash算法可以提高存儲空間的利用率,可以提高數(shù)據(jù)的查詢效率,也可以做數(shù)字簽名來保障數(shù)據(jù)傳遞的安全性。
對不同的關(guān)鍵字可能得到同一散列地址,現(xiàn)象稱碰撞。一組關(guān)鍵字和它們各自對應(yīng)的散列地址映射到一個有限的連續(xù)的地址集(區(qū)間)上,這種表便稱為散列表
總結(jié)
以上是生活随笔為你收集整理的Java基础面试典籍60+ | 大别山码将的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javaone_替代JavaOne 20
- 下一篇: Java的最新发展– 2018年4月下旬