網上一份java基礎面試題&整理的答案(或鏈接)①

網上看到一份號稱 史上最全的Java工程師面試題彙總,全會的話月薪至少3W+ ,那就根據裏面的內容,自己找找相關的答案

Java基礎知識

簡述:

1、==運算符是判斷兩個對象是不是同一個對象,即他們的地址是否相等

2、object類中equals與==是等效的

3、覆寫equals更多的是追求兩個對象在邏輯上的相等,你可以說是值相等,也可說是內容相等。(覆蓋以後,覆蓋equals時總要覆蓋hashCode )

4、hashCode用於返回對象的hash值,主要用於查找的快捷性,因爲hashCode也是在Object對象中就有的,所以所有Java對象都有hashCode,在HashTable和HashMap這一類的散列結構中,都是通過hashCode來查找在散列表中的位置的。

 

簡述:

1、Integer是int的包裝類,int則是java的一種基本數據類型 
2、Integer變量必須實例化後才能使用,而int變量不需要 
3、Integer實際是對象的引用,當new一個Integer時,實際上是生成一個指針指向此對象;而int則是直接存儲數據值 
4、Integer的默認值是null,int的默認值是0

簡述:

1、爲子類提供一個公共的類型;

2、封裝子類中重複內容(成員變量和方法);

3、定義有抽象方法,子類雖然有不同的實現,但該方法的定義是一致的。

 

簡述:

1、抽象類可以有構造方法,接口中不能有構造方法。

2、抽象類中可以有普通成員變量,接口中沒有普通成員變量

3、抽象類中可以包含靜態方法,接口中不能包含靜態方法

4、 一個類可以實現多個接口,但只能繼承一個抽象類。

5、接口可以被多重實現,抽象類只能被單一繼承

6、如果抽象類實現接口,則可以把接口中方法映射到抽象類中作爲抽象方法而不必實現,而在抽象類的子類中實現接口中方法

 

簡述:

我們是可以創建一個包含可變對象的不可變對象的,只需要謹慎一點,不要共享可變對象的引用就可以了,如果需要變化時,就返回原對象的一個拷貝,最常見的例子就是對象中包含一個日期對象的引用。

(補充說明:

不可變對象

  1. 可變對象:相對於不可變類,可變類創建實例後可以改變其成員變量值,開發中創建的大部分類都屬於可變類。
  2. 不可變對象:是指一個對象的狀態在對象被創建之後就不再變化。不可變對象對於緩存是非常好的選擇,因爲你不需要擔心它的值會被更改。
  3. 那麼對象是類實例化而來,怎麼創建一個不可變類呢?

創建一個不可變類

一個不可變類,必須要滿足以下條件:

(1)將類聲明爲final,所以它不能被繼承;

(2)將所有的成員聲明爲私有的,這樣就不允許直接訪問這些成員;

(3)對變量不要提供setter方法;

(4)將所有可變的成員聲明爲final,這樣只能對它們賦值一次;

(5)通過構造器初始化所有成員,進行深拷貝(deep copy);

(6)在getter方法中,不要直接返回對象本身,而是克隆對象,並返回對象的拷貝;

(7)如果要修改類的狀態,必須返回一個新的對象。

不可變類對於開發者來說有如下好處:

(1)易於設計,實現和使用

(2)使用過程中不容易導致出錯

(3)更加的安全,可以隨意地共用

(4)天然具備線程安全性,無需增加額外的同步操作

不可變對象的好處:

(1)不可變對象更容易構造,測試與使用;

(2)真正不可變對象都是線程安全的;

(3)不可變對象的使用沒有副作用(沒有保護性拷貝);

(4)對象變化的問題得到了避免;

(5)不可變對象的失敗都是原子性的;

(6)不可變對象更容易緩存,且可以避免null引用;

(7)不可變對象可以避免時間上的耦合;

 

簡述:

       【所謂多態,就是指程序中定義的引用變量所指向的具體類型通過該引用變量發出的方法調用編程時並不確定,而是在程序運行期間才確定,即一個引用變量到底會指向哪個類的實例對象,該引用變量發出的方法調用到底是哪個類中實現的方法,必須在由程序運行期間才能決定。因爲在程序運行時才確定具體的類,這樣,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類實現上,從而導致該引用變量調用的具體方法隨之改變,即不修改程序代碼就可以改變程序運行時所綁定的具體代碼,讓程序可以選擇多個運行狀態,這就是多態性。】

       指向子類的父類引用由於向上轉型了,它只能訪問父類中擁有的方法和屬性,而對於子類中存在而父類中不存在的方法,該引用是不能使用的,儘管是重載父類的方法也不可以。若子類重寫了父類中的某些方法,在調用該些方法的時候,必定是使用子類中定義的這些方法(動態連接、動態調用)

       對於面向對象來說,多態分爲編譯時多態運行時多態。其中編輯時多態是靜態的,主要是指方法的重載,它是根據參數列表的不同來區分不同的函數(如不帶參的構造函數和帶參的構造函數),通過編輯之後會變成兩個不同的函數,在運行時談不上多態。而運行時多態是動態的,它是通過動態綁定來實現的,也就是我們所說的多態性

       對於Java而言,它多態的實現機制遵循一個原則:當父類對象引用變量指向子類對象時,被引用對象的類型(也就是子類對象)而不是引用變量的類型決定了調用誰的成員方法,但是這個被調用的方法必須是在父類中定義過的,也就是說被子類覆蓋的方法。

       基於繼承實現的多態可以總結如下:對於引用子類的父類類型,在處理該引用時,它適用於繼承該父類的所有子類,子類對象的不同,對方法的實現也就不同,執行相同動作產生的行爲也就不同。(如果父類是抽象類,那麼子類必須要實現父類中所有的抽象方法,這樣該父類所有的子類一定存在統一的對外接口,但其內部的具體實現可以各異。這樣我們就可以使用頂層類提供的統一接口來處理該層次的方法。)

       在接口的多態中,指向接口的引用必須是指定這實現了該接口的一個類的實例程序,在運行時,根據對象引用的實際類型來執行對應的方法。

      繼承都是單繼承,只能爲一組相關的類提供一致的服務接口。但是接口可以是多繼承多實現,它能夠利用一組相關或者不相關的接口進行組合與擴充,能夠對外提供一致的服務接口。所以它相對於繼承來說有更好的靈活性。

鏈接裏有一個經典案例,最後的總結:

多態機制遵循的原則概括爲:當超類對象引用變量引用子類對象時,被引用對象的類型而不是引用變量的類型決定了調用誰的成員方法,但是這個被調用的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法,但是它仍然要根據繼承鏈中方法調用的優先級來確認方法,該優先級爲:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。

 

簡述:

String     StringBuffer     StringBuilder
String的值是不可變的,這就導致每次對String的操作都會生成新的String對象,不僅效率低下,而且浪費大量優先的內存空間  StringBuffer是可變類,和線程安全的字符串操作類,任何對它指向的字符串的操作都不會產生新的對象。每個StringBuffer對象都有一定的緩衝區容量,當字符串大小沒有超過容量時,不會分配新的容量,當字符串大小超過容量時,會自動增加容量  可變類,速度更快
不可變     可變    可變
   線程安全     線程不安全
   多線程操作字符串    單線程操作字符串

 

簡述:

1、

<? extends T>限定參數類型的上界:參數類型必須是T或T的子類型

<? super T> 限定參數類型的下界:參數類型必須是T或T的超類型
2、

上界<? extends T>不能往裏存,只能往外取

下界<? super T>不影響往裏存,但往外取只能放在Object對象裏

<? extends T> 只能用於方法返回,告訴編譯器此返參的類型的最小繼承邊界爲T,T和T的父類都能接收,但是入參類型無法確定,只能接受null的傳入
<? super T>只能用於限定方法入參,告訴編譯器入參只能是T或其子類型,而返參只能用Object類接收既不能用於入參也不能用於返參

3

PECS原則(Producer Extends Consumer Super):

頻繁往外讀取內容的,適合用上界Extends。

經常往裏插入的,適合用下界Super。

 

簡述

1、進程資源分配的最小單位線程程序執行的最小單位(資源調度的最小單位)
2、進程有自己的獨立地址空間,每啓動一個進程,系統就會爲它分配地址空間,建立數據表來維護代碼段、堆棧段和數據段,這種操作非常昂貴。
而線程是共享進程中的數據的,使用相同的地址空間,因此CPU切換一個線程的花費遠比進程要小很多,同時創建一個線程的開銷也比進程要小很多。
3、線程之間的通信更方便,同一進程下的線程共享全局變量、靜態變量等數據,而進程之間的通信需要以通信的方式(IPC)進行。不過如何處理好同步與互斥是編寫多線程程序的難點。
4、但是多進程程序更健壯,多線程程序只要有一個線程死掉,整個進程也死掉了,而一個進程死掉並不會對另外一個進程造成影響,因爲進程有自己獨立的地址空間。

 

簡述:
1.簡單區別:
final用於聲明屬性,方法和類,分別表示屬性不可交變,方法不可覆蓋,類不可繼承。
finally是異常處理語句結構的一部分,表示總是執行。
finalize是Object類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法,供垃圾收集時的其他資源回收,例如關閉文件等。

2.中等區別:
雖然這個單詞在Java中都存在,但是並沒太多關聯:
final:java中的關鍵字,修飾符。
A).如果一個類被聲明爲final,就意味着它不能再派生出新的子類,不能作爲父類被繼承。因此,一個類不能同時被聲明爲abstract抽象類的和final的類。
B).如果將變量或者方法聲明爲final,可以保證它們在使用中不被改變.
  1)被聲明爲final的變量必須在聲明時給定初值,而在以後的引用中只能讀取,不可修改。
  2)被聲明final的方法只能使用,不能重載。
finally:java的一種異常處理機制。
  finally是對Java異常處理模型的最佳補充。finally結構使代碼總會執行,而不管無異常發生。使用finally可以維護對象的內部狀態,並可以清理非內存資源。特別是在關閉數據庫連接這方面,如果程序員把數據庫連接的close()方法放到finally中,就會大大降低程序出錯的機率。
finalize:Java中的一個方法名。
Java技術使用finalize()方法在垃圾收集器將對象從內存中清除出去前,做必要的清理工作。這個方法是由垃圾收集器在確定這個對象沒被引用時對這個對象調用的。它是在Object類中定義的,因此所的類都繼承了它。子類覆蓋finalize()方法以整理系統資源或者執行其他清理工作。finalize()方法是在垃圾收集器刪除對象之前對這個對象調用的。

3.詳細區別參考鏈接

 

簡述:

序列化:可以將對象轉化成一個字節序列,便於存儲。
反序列化:將序列化的字節序列還原
優點:可以實現對象的"持久性”, 所謂持久性就是指對象的生命週期不取決於程序。

序列化方式一: 實現Serializable接口(隱式序列化)
通過實現Serializable接口,這種是隱式序列化(不需要手動),這種是最簡單的序列化方式,會自動序列化所有非static和 transient關鍵字修飾的成員變量。

序列化方式二:實現Externalizable接口。(顯式序列化)
Externalizable接口繼承自Serializable, 我們在實現該接口時,必須實現writeExternal()和readExternal()方法,而且只能通過手動進行序列化,並且兩個方法是自動調用的,因此,這個序列化過程是可控的,可以自己選擇哪些部分序列化

序列化方式三:實現Serializable接口+添加writeObject()和readObject()方法。(顯+隱序列化)

如果想將方式一和方式二的優點都用到的話,可以採用方式三, 先實現Serializable接口,並且添加writeObject()和readObject()方法。注意這裏是添加,不是重寫或者覆蓋。但是添加的這兩個方法必須有相應的格式。

1,方法必須要被private修飾                                ----->才能被調用
2,第一行調用默認的defaultRead/WriteObject(); ----->隱式序列化非static和transient
3,調用read/writeObject()將獲得的值賦給相應的值  --->顯式序列化

 

簡述:

  • parseInt(String s)--內部調用parseInt(s,10)(默認爲10進制)
  • 正常判斷null,進制範圍(radix在Character.MIN_RADIX與Character.MAX_RADIX之間是指在 2~~36之間),length等
  • 判斷第一個字符是否是符號位
  • 循環遍歷確定每個字符的十進制值
  • 通過*= 和-= 進行計算拼接
  • 判斷是否爲負值 返回結果。

(具體過程參考鏈接)

 

簡述:

java中靜態屬性和靜態方法可以被繼承,但是沒有被重寫而是被隱藏.

原因:
1). 靜態方法和屬性是屬於類的,調用的時候直接通過類名.方法名完成對,不需要繼承機制即可以調用。如果子類裏面定義了靜態方法和屬性,那麼這時候父類的靜態方法或屬性稱之爲"隱藏"。如果你想要調用父類的靜態方法和屬性,直接通過父類名.方法或變量名完成,至於是否繼承一說,子類是有繼承靜態方法和屬性,但是跟實例方法和屬性不太一樣,存在"隱藏"的這種情況。

2). 多態之所以能夠實現依賴於繼承、接口和重寫、重載(繼承和重寫最爲關鍵)。有了繼承和重寫就可以實現父類的引用指向不同子類的對象。重寫的功能是:"重寫"後子類的優先級要高於父類的優先級,但是“隱藏”是沒有這個優先級之分的。

3). 靜態屬性、靜態方法和非靜態的屬性都可以被繼承和隱藏而不能被重寫,因此不能實現多態,不能實現父類的引用可以指向不同子類的對象。非靜態方法可以被繼承和重寫,因此可以實現多態。

靜態屬性和靜態方法可以被繼承
靜態方法不可以被重寫,不能實現多態

 

簡述:

什麼是內部類?
內部類是定義在另一個類中的類;即內部類對象引用了實例化該內部對象的外圍類對象。

爲什麼需要內部類?
內部類方法可以訪問該類定義所在的作用域中的數據,包括私有數據。
內部類可以對同一個包中的其他類隱藏起來。
當想要定義一個回調函數且不想編寫大量代碼時,使用匿名內部類比較便捷。

內部類的分類
一、成員內部類

存在於某個類的內部的非靜態類,與全局屬性或者方法同級的內部類就是成員內部類。

成員內部類特點:
①成員內部類可以無條件訪問外部類的所有成員屬性和成員方法(包括靜態成員和私有成員)。
②成員內部類和外部類的屬性和方法名同名時,外部類的屬性和方法會隱藏;但可以通過外部類.this.成員變量的方式訪問外部類的屬性和方法。
③外部類必須通過成員內部類的對象來訪問內部類的屬性和方法。
④成員內部類對象會隱式的引用一個外部類對象。(可以解釋第一點)
⑤成員內部類可以有public\private\protected以及默認訪問權限。

二、靜態內部類
在成員內部類的基礎上加上一個static關鍵字就是靜態內部類。

靜態內部類的特點:
不需要依賴外部類。
不能使用外部類的非靜態屬性和方法。

項目中的使用:
Java集合類HashMap內部就有一個靜態內部類Entry。Entry是HashMap存放元素的抽象類,HashMap內部維護Entry數組用來存放元素,但是Entry對使用者是透明的。像這種和外部類關係密切的,且不依賴外部類實例的,都可以使用靜態內部類。

三、局部內部類
是定義在一個方法或者一個作用域裏面的類,就是局部類。它與成員內部類的區別在於局部內部類的訪問僅在於方法內或者作用域內。
(局部內部類是嵌套在方法和作用域內的,對於這個類的使用主要是應用與解決比較複雜的問題,想創建一個類來輔助我們的解決方案,然而又不希望這個類是公共可用的,所以就產生了局部內部類,局部內部類和成員內部類一樣被編譯,只是它的作用域發生了改變,它只能在該方法和屬性中被使用,出了該方法和屬性就會失效。)

局部內部類的特點:
不能有private、public、protected和static等修飾符,與局部變量類似。
只能在定義局部內部類的方法或者作用域中實例化;
局部內部類的對象不能使用該內部類所在方法或者作用域的非final局部變量(爲什麼?);

項目中的使用:
如果一個類只在某個方法中使用,則可以考慮使用局部類。

四、匿名內部類
不定義類的名字,在使用的地方直接定義對象。

匿名內部類的特點:
唯一一種沒有構造器的類;匿名內部類在編譯時,編譯器會自動起名xxx$1.class;
匿名內部類不能存在任何靜態的變量、方法等;
匿名內部類是局部內部類的特例;
大部分匿名內部類用於接口返回;
匿名內部類是沒有訪問修飾符的。
new 匿名內部類,這個類首先是要存在的。
當所在方法的形參需要被匿名內部類使用,那麼這個形參就必須爲final。
匿名內部類沒有明面上的構造方法,編譯器會自動生成一個引用外部類的構造方法。

項目中的使用:
匿名內部類使用廣泛,比如我們常用的綁定監聽的時候。
使用匿名內部類,創建線程

(詳細內容參考鏈接)

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章