Java面試寶典之—-java基礎(含答案)

Clay-發表於2018-12-21

一 JAVA基礎

1. JAVA中的幾種基本資料型別是什麼,各自佔用多少位元組

int        32bit   short   16bit
long     64bit   byte     8bit
char     16bit   float   32bit
double   64bit   boolean 1bit

 ============================================================

2. String類能被繼承嗎,為什麼?

public final class String

    implements java.io.Serializable, Comparable<String>, CharSequence

String 被final修飾了,所有不能被繼承。

1.final修飾的物件不能被修改;

2.final修飾的類不能被繼承;

3.final修飾的方法不能被重寫;

 ==================================================================

3. String,Stringbuffer,StringBuilder的區別。

1.可變與不可變

  String類中使用字元陣列儲存字串,如下就是,因為有“final”修飾符,所以可以知道string物件是不可變的。

    private final char value[];

  StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字元陣列儲存字串,如下就是,可知這兩種物件都是可變的。

    char[] value;

2.是否多執行緒安全

  String中的物件是不可變的,也就可以理解為常量,顯然執行緒安全

  AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。

  StringBuffer對方法加了同步鎖或者對呼叫的方法加了同步鎖,所以是執行緒安全的。看如下原始碼

最後,如果程式不是多執行緒的,那麼使用StringBuilder效率高於StringBuffer。

 ==================================================================

4 . ArrayList和LinkedList有什麼區別。

ArrayList和Vector使用了陣列的實現,

LinkedList使用了迴圈雙向連結串列資料結構。 場景使用不同

 

對ArrayList和LinkedList而言,在列表末尾增加一個元素所花的開銷都是固定的。對ArrayList而言,主要是在內部陣列中增加一項,指向所新增的元素,偶爾可能會導致對陣列重新進行分配;而對LinkedList而言,這個開銷是統一的,分配一個內部Entry物件。
2.在ArrayList的中間插入或刪除一個元素意味著這個列表中剩餘的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。
3.LinkedList不支援高效的隨機元素訪問。
4.ArrayList的空間浪費主要體現在在list列表的結尾預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗相當的空間
       可以這樣說:當操作是在一列資料的後面新增資料而不是在前面或中間,並且需要隨機地訪問其中的元素時,使用ArrayList會提供比較好的效能;當你的操作是在一列資料的前面或中間新增或刪除資料,並且按照順序訪問其中的元素時,就應該使用LinkedList了。

 ==================================================================

5. 講講類的例項化順序,比如父類靜態資料,建構函式,欄位,子類靜態資料,建構函式,欄位,當new的時候,他們的執行順序。

類的例項化順序:先靜態再父子

父類靜態資料->子類靜態資料->父類欄位->子類欄位->父類建構函式->子類建構函式

 ==================================================================

6. Map區別

用過哪些Map類,都有什麼區別,HashMap是執行緒安全的嗎,併發下使用的Map是什麼,他們內部原理分別是什麼,比如儲存方式,hashcode,擴容,預設容量等。

最常用的Map實現類有:HashMap,ConcurrentHashMap(jdk1.8),LinkedHashMap,TreeMap,HashTable;

其中最頻繁的是HashMap和ConcurrentHashMap,他們的主要區別是HashMap是非執行緒安全的。ConcurrentHashMap是執行緒安全的。

併發下可以使用ConcurrentHashMap和HashTable,他們的主要區別是:

1.ConcurrentHashMap的hash計算公式:(key.hascode()^ (key.hascode()>>> 16)) & 0x7FFFFFFF

   HashTable的hash計算公式:key.hascode()& 0x7FFFFFFF

2.HashTable儲存方式都是連結串列+陣列,陣列裡面放的是當前hash的第一個資料,連結串列裡面放的是hash衝突的資料

 ConcurrentHashMap是陣列+連結串列+紅黑樹

3.預設容量都是16,負載因子是0.75。就是當hashmap填充了75%的busket是就會擴容,最小的可能性是(16*0.75),一般為原記憶體的2倍

4 .執行緒安全的保證:HashTable是在每個操作方法上面加了synchronized來達到執行緒安全,ConcurrentHashMap執行緒是使用CAS(compore and swap)來保證執行緒安全的

 ==================================================================

7. JAVA8的ConcurrentHashMap為什麼放棄了分段鎖,有什麼問題嗎,如果你來設計,你如何設計。

jdk8 放棄了分段鎖而是用了Node鎖,減低鎖的粒度,提高效能,並使用CAS操作來確保Node的一些操作的原子性,取代了鎖。

但是ConcurrentHashMap的一些操作使用了synchronized鎖,而不是ReentrantLock,雖然說jdk8的synchronized的效能進行了優化,但是我覺得還是使用ReentrantLock鎖能更多的提高效能

 ==================================================================

8.  有沒順序的 Map 實現類,如果有,他們是怎麼保證有序的 。 順序的 Map 實現類:LinkedHashMap,TreeMap

LinkedHashMap 是基於元素進入集合的順序或者被訪問的先後順序排序,TreeMap 則是基於元素的固有順序 (由 Comparator 或者 Comparable 確定)。

 ==================================================================

9. 抽象類和介面的區別,類可以繼承多個類麼,介面可以繼承多個介面麼,類可以實現多個介面麼。抽象類和介面的區別:

1.抽象類可以有自己的實現方法,介面在jdk8以後也可以有自己的實現方法(default)

2.抽象類的抽象方法是由非抽象類的子類實現,介面的抽象方法有介面的實現類實現

3.介面不能有私有的方法跟物件,抽象類可以有自己的私有的方法跟物件

類不可以繼承多個類,介面可以繼承多個介面,類可以實現多個介面

 ==================================================================

10. 繼承和聚合的區別在哪。

繼承:指的是一個類(稱為子類、子介面)繼承另外的一個類(稱為父類、父介面)的功能,並可以增加它自己的新功能的能力,繼承是類與類或者介面與介面之間最常見的關係;在Java中此類關係通過關鍵字extends明確標識,在設計時一般沒有爭議性;

聚合:聚合是關聯關係的一種特例,他體現的是整體與部分、擁有的關係,即has-a的關係,此時整體與部分之間是可分離的,他們可以具有各自的生命週期,部分可以屬於多個整體物件,也可以為多個整體物件共享;比如計算機與CPU、公司與員工的關係等;表現在程式碼層面,和關聯關係是一致的,只能從語義級別來區分;

 ==================================================================

11. 講講你理解的nio。他和bio的區別是啥,談談reactor模型。

BIO:同步阻塞式IO,伺服器實現模式為一個連線一個執行緒,即客戶端有連線請求時伺服器端就需要啟動一個執行緒進行處理,如果這個連線不做任何事情會造成不必要的執行緒開銷,當然可以通過執行緒池機制改善。
NIO:同步非阻塞式IO,伺服器實現模式為一個請求一個執行緒,即客戶端傳送的連線請求都會註冊到多路複用器上,多路複用器輪詢到連線有I/O請求時才啟動一個執行緒進行處理。

reactor模型:反應器模式(事件驅動模式):當一個主體發生改變時,所有的屬體都得到通知,類似於觀察者模式。

 ==================================================================

12. 反射的原理,反射建立類例項的三種方式是什麼

反射的原理:如果知道一個類的名稱/或者它的一個例項物件, 就能把這個類的所有方法和變數的資訊(方法名,變數名,方法,修飾符,型別,方法引數等等所有資訊)找出來。

反射建立類例項的三種方式:

1.Class.forName(“com.A”);

2.new A().getClass();

3.A.class;

 ==================================================================

13. 反射中,Class.forName和ClassLoader區別。

class.forName()除了將類的.class檔案載入到jvm中之外,還會對類進行解釋,執行類中的static塊。
classLoader只幹一件事情,就是將.class檔案載入到jvm中,不會執行static中的內容,只有在newInstance才會去執行static塊。

 ==================================================================

14.  描述動態代理的幾種實現方式,分別說出相應的優缺點

動態代理有兩種實現方式,分別是:jdk動態代理和cglib動態代理

jdk動態代理的前提是目標類必須實現一個介面,代理物件跟目標類實現一個介面,從而避過虛擬機器的校驗。

cglib動態代理是繼承並重寫目標類,所以目標類和方法不能被宣告成final。

 ==================================================================

15. 動態代理與cglib實現的區別。

動態代理有兩種實現方式,分別是:jdk動態代理和cglib動態代理

jdk動態代理的前提是目標類必須實現一個介面,代理物件跟目標類實現一個介面,從而避過虛擬機器的校驗。

cglib動態代理是繼承並重寫目標類,所以目標類和方法不能被宣告成final。

 ==================================================================

16.  為什麼cglib方式可以對介面實現代理。

 cglib動態代理是繼承並重寫目標類,所以目標類和方法不能被宣告成final。而介面是可以被繼承的。

  ==================================================================

17. final的用途。

1.final修飾的物件不能被修改;

2.final修飾的類不能被繼承;

3.final修飾的方法不能被重寫;

 ==================================================================

18  如何在父類中為子類自動完成所有的hashcode和equals實現?這麼做有何優劣。

父類的equals不一定滿足子類的equals需求。比如所有的物件都繼承Object,預設使用的是Object的equals方法,在比較兩個物件的時候,是看他們是否指向同一個地址。

但是我們的需求是物件的某個屬性相同,就相等了,而預設的equals方法滿足不了當前的需求,所以我們要重寫equals方法。

如果重寫了equals 方法就必須重寫hashcode方法,否則就會降低map等集合的索引速度。

 ==================================================================

20.  請結合OO設計理念,談談訪問修飾符public、private、protected、default在應用設計中的作用

OO設計理念:封裝、繼承、多型

封裝,也就是把客觀事物封裝成抽象的類,並且類可以把自己的資料和方法只讓可信的類或者物件操作,對不可信的進行資訊隱藏。所以我們可以通過public、private、protected、default 來進行訪問控制

關鍵字

類內部

本包

子類

外部包

public 

protected

×

default 

×

×

private

×

×

×

java訪問控制符的含義和使用情況

 ==================================================================

21.  深拷貝和淺拷貝區別。

淺拷貝只拷貝指標,深拷貝就是拷貝他的值,重新生成的對像。

 ==================================================================

23. error和exception的區別,CheckedException,RuntimeException的區別。

Error(錯誤)表示系統級的錯誤和程式不必處理的異常,是java執行環境中的內部錯誤或者硬體問題。比如:記憶體資源不足等。對於這種錯誤,程式基本無能為力,除了退出執行外別無選擇,它是由Java虛擬機器丟擲的。
    Exception(違例)表示需要捕捉或者需要程式進行處理的異常,它處理的是因為程式設計的瑕疵而引起的問題或者在外的輸入等引起的一般性問題,是程式必須處理的。
Exception又分為執行時異常,受檢查異常。
       RuntimeException(執行時異常),表示無法讓程式恢復的異常,導致的原因通常是因為執行了錯誤的操作,建議終止程式,因此,編譯器不檢查這些異常。
       CheckedException(受檢查異常),是表示程式可以處理的異常,也即表示程式可以修復(由程式自己接受異常並且做出處理), 所以稱之為受檢查異常。

 ==================================================================

24.  請列出5個執行時異常。

NullPointerException

IndexOutOfBoundsException

ClassCastException

ArrayStoreException

BufferOverflowException

 ==================================================================

25. 在自己的程式碼中,如果建立一個java.lang.String物件,這個物件是否可以被類載入器載入?為什麼。

不可以,雙親委派模式會保證父類載入器先載入類,就是BootStrap(啟動類)載入器載入jdk裡面的java.lang.String類,而自定義的java.lang.String類永遠不會被載入到

 ==================================================================

26. 說一說你對java.lang.Object物件中hashCode和equals方法的理解。在什麼場景下需要重新實現這兩個方法

父類的equals不一定滿足子類的equals需求。比如所有的物件都繼承Object,預設使用的是Object的equals方法,在比較兩個物件的時候,是看他們是否指向同一個地址。

但是我們的需求是物件的某個屬性相同,就相等了,而預設的equals方法滿足不了當前的需求,所以我們要重寫equals方法。

如果重寫了equals 方法就必須重寫hashcode方法,否則就會降低map等集合的索引速度。

 ==================================================================

27.  在jdk1.5中,引入了泛型,泛型的存在是用來解決什麼問題。

泛型的好處是在編譯的時候檢查型別安全,並且所有的強制轉換都是自動和隱式的,提高程式碼的重用率。==================================================================

28. 有沒可能 2個不相等的物件有同hashcode。

有可能,最簡單的方法,百分百實現的方式就是重寫hascode();

 ==================================================================

29.  Java中的HashSet內部是如何工作的。

public HashSet() {

    map = new HashMap<>();}

預設使用的是HaseMap;

 ==================================================================

30什麼是序列化,怎麼序列化,為什麼序列化,反序列化會遇到什麼問題,如何解決。

序列化是一種用來處理物件流的機制 ,所謂物件流就是將物件的內容進行流化。

序列化是為了解決在對物件流進行讀寫操作時所引發的問題。

序列化的實現:將需要被序列化的類實現Serializable介面,該介面沒有需要實現的方法,implements Serializable只是為了標註該物件是可被序列化的,然後使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(物件流)物件,接著,使用ObjectOutputStream物件的writeObject(Object obj)方法就可以將引數為obj的物件寫出(即儲存其狀態),要恢復的話則用輸入流;

相關文章