JAVA基礎面試試題及答案(阿里面試題-JAVA基礎篇)

1.JAVA中的幾種基本數據類型是什么,各自占用多少字節。
答:
int 32bit
short 16bit
long 64bit
byte 8bit
char 16bit
float 32bit
double 64bit
boolean 1bit

2.String類能被繼承嗎,為什么。
答:String 是final類,String也是java中真正的Immutable。

3.String,Stringbuffer,StringBuilder的區別。
答:1.String類是不可變的,所謂不可變意思就是創建一個類后任何對String的改變都 會引發新的String對象的生成,應為String是不可變的因此不存在線程安全的問題;2.Stringbuffer,StringBuilder是可變的,不會每次都生成新對象,但是有容量大小,默認容量為16,當超過最大容量時會擴容,為了減少擴容的開銷,新建時盡量設置容量大小;3.StringBuffer和StringBuilder類的區別是StringBuffer是線程安全,打開StringBuffer會發現各種修改數據的方法都加上 synchronized 關鍵字實現的,簡單暴力,StringBuilder 是 Java 1.5 中新增的,在能力上和 StringBufer 沒有本質區別,但是它去掉了線程安全的部分,有效減小了開銷,是絕大部分情況下進行字符串拼接的首選。4、我們實際使用中也不用過于糾結是使用String還是StringBuffer與StringBufer,現代JDK中編譯時就會進行優化會將字符串拼接(+號拼接)優化為StringBuffer,甚至如"a"+"b"這樣的憑借會直接編譯優化為"ab",因此還是優化考慮代碼的可讀性和美觀,但是通過for循環憑借字符串傳時請使用StringBuffer或StringBufer。

4.ArrayList和LinkedList有什么區別。
答:1、數據結構不同,ArrayList是Array(動態數組)的數據結構,LinkedList是Link(鏈表)的數據結構,ArrayList數據滿的時候需要擴容,但LinkedList不需要,但是linkedList需要維護前后節點信息,因此會有額外的內存開銷;2、當隨機訪問List(get和set操作)時,ArrayList比LinkedList的效率更高;如果能預估ArrayList大概長度,設置默認容量,防止頻繁擴容,優先是用ArrayList,此時查詢、新增性能都比較好,但如果存在頻繁刪除操作時優先使用linkedList;

5.講講類的實例化順序,比如父類靜態數據,構造函數,字段,子類靜態數據,構造函數,字段,當new的時候,他們的執行順序。
答:順序為:父類靜態變量 ->父類靜態代碼塊->子類靜態變量->子類靜態代碼塊、
父類非靜態變量(父類實例成員變量)->父類構造函數->子類非靜態變量(子類實例成員變量)->子類構造函數。

6.用過哪些Map類,都有什么區別,HashMap是線程安全的嗎,并發下使用的Map是什么,他們內部原理分別是什么,比如存儲方式,hashcode,擴容,默認容量等。
答:1、HashTable、HashMap、TreeMap都是常見的Map實現都是以鍵值對方式存儲,HashTable本身是同步的不支持null的鍵和值,由于同步導致性能開銷,一班不推薦使用,默認初始容量為11,擴容2*原數組長度+1;HashMap不是同步的,支持null鍵和值,在數量比較小的時候HashMap get、put都能達到常數時間的性能,所以是絕大多數利用鍵值存取場景的首選,因為HashMap是采用數組建單向鏈表的是數據結構,因此在hash沖突較多的情況小查詢性能驟降,因此JDK8開始加入了紅黑樹,默認鏈表長度超過8時變為紅黑樹這樣查詢、新增都能達到O(log n)的性能,HashMap有兩個關鍵的屬性即負載因子(默認0.75默認)和容量(默認16)容量只能是2的冪數,因此擴容都是翻倍擴;LInkedHashMap和HashMap類似,加入了雙向鏈表,遍歷順序符合插入順序;TreeMap 則是基于紅黑樹的一種提供順序訪問的 Map ,和 HashMap 不同,它的 get 、 put 、 remove 之類操作都是 O(log n)的時間復雜度,具體順序可以由指定,默認是按鍵值的升序排序;2、并發下推薦使用ConcurrentHashMap, Collections.synchronizedMap也可以使用來獲取一個同步包裝容器,但是性能較差不推薦使用,ConcurrentHashMap 在JDK1.7是基于分段鎖實現并發控制,也就是將內部進行分段(Segment),里面則是HashEntry的數組,和HashMap類似,哈希相同的條目也是以鏈表形式存放;JDK1.8 請看第7題;

image

7.JAVA8的ConcurrentHashMap為什么放棄了分段鎖,有什么問題嗎,如果你來設計,你如何設計。
答:分段式鎖的粒度任然很大,默認16的分段并不能帶來很好的并發性能,JDK1.8的實現已經摒棄了Segment的概念,而是直接用Node數組+鏈表+紅黑樹的數據結構來實現,并發控制使用Synchronized和CAS來操作,在沒有hash沖突的情況下直接使用cas來操作,沒有鎖的性能開銷,當hash沖突時,則直接用鏈表第一個object加鎖,這里加的鎖是synchronized,雖然效率不如 ReentrantLock, 但節約了空間,整個看起來就像是優化過且線程安全的HashMap。

8.有沒有有順序的Map實現類,如果有,他們是怎么保證有序的。
答:常見linkedHashMap、TreeMap;LinkedHashMap是基于鏈表來實現數據插入有序的;TreeMap是基于比較器Comparator來實現有序,TreeMap以紅黑樹的形式存儲,本身就是一個二叉查找樹。

9.抽象類和接口的區別,類可以繼承多個類么,接口可以繼承多個接口么,類可以實現多個接口么。
答:1、接口是對行為的抽象,它是抽象方法的集合,利用接口可以達到 API 定義和實現分離的目的。接口,不能實例化;不能包含任何非常量成員,任何 feld 都是隱含著 public static final 的意義;同時,沒有非靜態方法實現,也就是說要么是抽象方法,要么是靜態方法。 抽象類是不能實例化的類,用 abstract 關鍵字修飾 class ,其目的主要是代碼重用。除了不能實例化,形式上和一般的 Java 類并沒有太大區別,可以有一個或者多個抽象方法,也可以沒有抽象方法。抽象類大多用于抽取相關 Java 類的共用方法實現或者是共同成員變量,然后通過繼承的方式達到代碼復用的目的。 Java 8以后,接口也是可以有方法實現的,個人認為以后抽象類和接口應該卻別越來越少甚至合并。2、類只能繼承一個類,但可以實現多個接口,接口可以繼承多個接口,不允許類多重繼承的主要原因是,如果A同時繼承B和C,而B和C同時有一個D方法,A如何決定該繼承那一個呢不允許類多重繼承的主要原因是,如果A同時繼承B和C,而B和C同時有一個D方法,A如何決定該繼承那一個呢?但接口不存在這樣的問題,接口全都是抽象方法繼承誰都無所謂,所以接口可以繼承多個接口。

10.繼承和聚合的區別在哪。
答:繼承他是is-a的關系,指一個類繼承另外一個類的功能;聚合他是has-a。

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

答:
BIO:同步并阻塞,服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程并處理,如果這個連接不做任何事情會造成不必要的開銷,當然可以通過線程池機制改善;

**NIO **:同步非阻塞,服務器實現模式為一個請求一個線程,即客戶端發送的連接請求都會注冊到多路復用器上,多路復用器輪詢到連接有IO請求時才啟動一個線程進行處理

NIO2(AIO):異步非阻塞,服務器實現模式為一個有效請求一個線程,客戶端的I/O請求都是由OS先完成了再通知服務器應用去啟動線程進行處理;

reactor模型:NIO基于Reactor,當socket有流可讀或可寫入socket,操作系統會相應的通知引用程序進行處理,應用再將流讀取到緩沖區或寫入操作系統。也就是,不是一個鏈接就要對應一個處理線程,而是一個有效請求對應一個線程,當連接沒有數據時,是沒有工作線程來處理的

image

12.反射的原理,反射創建類實例的三種方式是什么。
答:原理:類的字節碼加載到JVM后,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。

反射創建類實例的三種方式:

  • Class.forName(“com.A”)
  • new A().getClass()
  • A.class

13.反射中,Class.forName和ClassLoader區別 。
答:Class.forName()和ClassLoader都可以對類進行加載。ClassLoader就是遵循雙親委派模型最終調用啟動類加載器的類加載器,實現的功能是“通過一個類的全限定名來獲取描述此類的二進制字節流”,獲取到二進制流后放到JVM中。Class.forName()方法實際上也是調用的CLassLoader來實現的,但是Class.forName()會對加載的類進行初始化,會執行類中的靜態代碼塊,以及對靜態變量的賦值等操作。classLoader僅僅就是將.class文件加載到jvm。

14.描述動態代理的幾種實現方式,分別說出相應的優缺點。
答:主要的有jdk動態代理和cglib動態代理兩種方式:
jdk動態代理
優點:1、最小化依賴關系,減少依賴意味著簡化開發和維護,JDK本身的支持,可能比cglib更加可靠;2、平滑進行JDK版本升級,而字節碼類庫通常需要進行更新以保證在新版Java上能夠使用。3、代碼實現簡單。
缺點:目標類必須實現一個接口,使用范圍受限;
cglib:
優點:1、用更高性能的字節碼操作機制,性能稍高,類似還有ASM、Javassist等;
2、有的時候調用目標可能不便實現額外接口,從某種角度看,限定調用者實現接口是有些侵入性的實踐,類似cglib動態代理就沒有這種限制;
3、只操作我們關心的類,而不必為其他相關類增加工作量;
缺點:1、由于cglib是基于繼承的方式實現類的動態代理,因此無法實現對final方法的代理,也不能完全算缺點的,只是個坑,大家注意即可;

15.動態代理與cglib實現的區別。
答:參考考第14題目,這里補充一點:jdk動態代理是由java內部的反射機制來實現的,cglib動態代理底層則是借助asm來實現的,對指定的目標生成一個子類,并覆蓋其中方法實現增強,但因為采用的是繼承,所以不能對final修飾的類進行代理。

16.為什么CGlib方式可以對接口實現代理。
答:cglib動態代理是繼承并重寫目標類,所以目標類和方法不能被聲明成final,而接口是可以被繼承的。

17.final的用途。
答:1、使用fnal修飾參數或者變量,也可以清楚地避免意外賦值導致的編程錯誤,同時提升代碼可讀性;2、final變量產生了某種程度的不可變(immutable)的效果,所以,可以用于保護只讀數據,尤其是在并發編程中,因為明確地不能再賦值fnal變量,有利于減少額外的同步開銷,也可以省去一些防御性拷貝的必要;3、被final修飾的方法,JVM會嘗試為之尋求內聯,這對于提升Java的效率是非常重要的。因此,假如能確定方法不會被繼承,那么盡量將方法定義為final的。

18.寫出三種單例模式實現 。

答:
懶漢模式

public class Singleton { 
    private static Singleton instance; 
    private Singleton (){} 
    
    public static Singleton getInstance() { 
  
       if (instance == null) { 
            instance = new Singleton(); 
       } 

        return instance; 
    } 

}

餓漢模式

public class Singleton { 

    private static Singleton instance = new Singleton(); 

    private Singleton (){} 

    public static Singleton getInstance() { 

    return instance; 

    } 

}

雙重鎖模式

public class Singleton { 

    private volatile static Singleton singleton; 

    private Singleton (){} 

    public static Singleton getSingleton() { 

    if (singleton == null) { 

        synchronized (Singleton.class) { 

        if (singleton == null) { 

            singleton = new Singleton(); 

        } 

        } 

    } 

    return singleton; 

    } 

}

靜態內部類單例模式

public class Singleton {

    private Singleton(){

    }

      public static Singleton getInstance(){ 

        return Inner.instance; 

    } 

    private static class Inner { 

        private static final Singleton instance = new Singleton(); 

    } 

}

枚舉單例模式(effective java中推薦)

public enum Singleton {

    INSTANCE;

    public void doSomething() {

        System.out.println("doSomething");

    }

}

//使用方式

Singleton.INSTANCE.doSomething();

19.如何在父類中為子類自動完成所有的hashcode和equals實現?這么做有何優劣。
答:其實前半句的問題有點懵,直接父類中重寫hashcode和equals實現即可,但是父類的hashcode和equals并不一定能滿足子類的要求,比如所有的對象都繼承Object,默認使用的是Object的equals方法,在比較兩個對象的時候,是看他們是否指向同一個地址,但是我們的需求是對象的某個屬性相同,就相等了,而默認的equals方法滿足不了當前的需求,所以我們要重寫equals方法。
如果重寫了equals 方法就必須重寫hashcode方法,否則就會降低map等集合的索引。

20.請結合OO設計理念,談談訪問修飾符public、private、protected、default在應用設計中的作用。
答:OO設計理念:抽象、封裝、繼承、多態;封裝也就是把客觀事物封裝成抽象的類,并且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏,所以我們可以通過public、private、protected、default 來進行訪問控制;

21.深拷貝和淺拷貝區別。
答:淺拷貝基本類型拷貝值,引用類型只拷貝引用地址;深拷貝引用類型也是拷貝他的值,重新生成的對像,clone出來對象與原對象互不影響。

22.數組和鏈表數據結構描述,各自的時間復雜度。
答:數組是將元素在內存中連續存放,由于每個元素占用內存相同,可以通過下標迅速訪問數組中任何元素。插入、刪除都可能需要移動的元素,最差的時間復雜度是O(N),根據下標獲取元素的復雜度是O(1),且數組的大小是固定不可變的。鏈表恰好相反,鏈表中的元素在內存中不是順序存儲的,而是通過存在元素中的指針聯系到一起,需要額外的空間來存儲相連節點的指針,鏈表增加和刪除時只要修改元素中的指針即可,時間復雜度為O(1),如果應用需要經常插入和刪除元素你就需要用鏈表。

23.error和exception的區別,CheckedException,RuntimeException的區別。
答: Exception 是程序正常運行中可以預料的異常,可能并且應該被捕獲,并進行相應處理。Error 是指在正常情況下,不大可能出現的情況,絕大部分的 Error 都會導致程序(比如 JVM 自身)處于非正常的、不可恢復狀態。既然是非正常情況,所以不便于也不需要捕獲,常見的比如 OutOfMemoryError 之類,都是 Error 的子類。
CheckedException 是可檢查異常,需要程序顯式捕獲處理;
RuntimeException 是不檢查異常,不檢查異常就是所謂的運行時異常,類似NullPointerException 、 ArrayIndexOutOfBoundsException 之類,通常是可以編碼避免的邏輯錯誤,具體根據需要來判斷是否需要捕獲,并不會在編譯期強制要求。
異常處理的基本原則:1、 盡量不要捕獲類似Exception這樣的通用異常,而是應該捕獲特定異常;2、 不要生吞(swallow)異常;

24.請列出5個運行時異常。
答:ClassCastException(類轉換異常)、IndexOutOfBoundsException(數組越界)、NullPointerException(空指針)、ArithmeticException(算術運算異常)BufferOverflowException(內存溢出)、ArrayStoreException (向數組中存放與聲明類型不兼容對象異常)

25.在自己的代碼中,如果創建一個java.lang.String類,這個類是否可以被類加載器加載?為什么。
答:不可以;類加載器層次:自定義類加載器 >> 應用程序類加載器 >> 擴展類加載器 >> 啟動類加載器;雙親委派機制:如果一個類加載器收到了類加載的請求,它首先不會自己嘗試去加載這個類,而是把這個請求委派給父類加載器,每一個層次的類加載器都是如此,因此所有的加載請求最終到達頂層的啟動類加載器(BootStrap),只有當父類加載器反饋自己無法完成加載請求時,子類加載器才會嘗試自己去加載,所以BootStrap(啟動類)加載器加載jdk里面的java.lang.String類,而自定義的java.lang.String類永遠不會被加載到。

26.說一說你對java.lang.Object對象中hashCode和equals方法的理解。在什么場景下需要重新實現這兩個方法。
答:Object的對象equals方法是判斷兩個對象是否指向同一個地址,并不一定能滿足我們的需求,比如String就重寫了Object的equals方法,如果重寫了equals 方法就必須重寫hashcode方法,否則就會降低map等集合的索引速度。

27.在jdk1.5中,引入了泛型,泛型的存在是用來解決什么問題。
答:我們在編寫程序時,經常遇到兩個模塊的功能非常相似,只是一個是處理int數據,另一個是處理string數據,或者其他自定義的數據類型,但我們沒有辦法,只能分別寫多個方法處理每個數據類型,因為方法的參數類型不同,當然我們也可以用一個通用類型處理,但這樣都把問題留個運行時了,這樣并不安全可讀性也差,因此這個時候泛型就出現了,類在進行定義的時候可以使用一個標記,此標記就表示類中屬性或者方法以及參數的類型,標記在使用的時候才會確定下來,而且泛型的好處是在編譯時檢查類型安全,并且所有的強制轉換都是自動和隱式的,提高了代碼的重用率,避免在運行時出現 ClassCastException。

28.這樣的a.hashcode() 有什么用,與a.equals(b)有什么關系。
答:hhashCode() 的作用是獲取哈希碼,也稱為散列碼;它實際上是返回一個int整數,這個哈希碼的作用是確定該對象在哈希表中的索引位置,因為hashCode() 在Object類中,所以任何類都可以重寫hashCode() ,但是如果哪個類沒有重寫hashCode() ,當調用hashCode() 默認行為是對堆上的對象產生獨特值。

hashCode()與equals()的相關規定:

  • 如果兩個對象相等,則hashcode一定也是相同的;
  • 兩個對象相等,對兩個對象分別調用equals方法都返回true;
  • 兩個對象有相同的hashcode值,它們也不一定是相等的;
  • equals方法被覆蓋過,則hashCode方法也必須被覆蓋;
  • hashCode()的默認行為是對堆上的對象產生獨特值。如果沒有重寫hashCode(),則該類的兩個對象無論如何都不會相等;

29.有沒有可能2個不相等的對象有相同的hashcode。
答:有可能,最粗暴的辦法就是重新類的hashcode方法equals,讓hashcode相等,equals不相等。

30.Java中的HashSet內部是如何工作的。
答:HashSet 的內部采用 HashMap來實現,由于 Map 需要 key 和 value,所以HashSet中所有 key 的都有一個默認value,類似于 HashMap,HashSet 不允許重復的 key,只允許有一個null key,意思就是 HashSet 中只允許存儲一個 null 對象;HashSet的部分源代碼:

private transient HashMap<E,Object> map;

private static final Object PRESENT = new Object();

public HashSet() {

    map = new HashMap<>();

}

public boolean add(E e) {

    return map.put(e, PRESENT)==null;

}

31.什么是序列化,怎么序列化,為什么序列化,反序列化會遇到什么問題,如何解決。
答: 1、Java序列化是指把Java對象轉換為字節序列的過程;而Java反序列化是指把字節序列恢復為Java對象的過程;2、java 通過 java.io.ObjectOutputStream、java.io.ObjectInputStream API來完成序列化和反序列化;3、當兩個進程進行遠程通信時,可以相互發送各種類型的數據,包括文本、圖片、音頻、視頻等, 而這些數據都會以二進制序列的形式在網絡上傳送。那么當兩個Java進程進行通信時,能否實現進程間的對象傳送呢?答案是可以的。如何做到呢?這就需要Java序列化與反序列化了。換句話說,一方面,發送方需要把這個Java對象轉換為字節序列,然后在網絡上傳送;另一方面,接收方需要從字節序列中恢復出Java對象;也可以實現數據的持久化,通過序列化可以把數據永久地保存到硬盤上;4、序列化時是通過判斷類的serialVersionUID來驗證版本一致性的,如果修改了serialVersionUID的值就會導致反序列化失敗。

32.java8的新特性。

答:主要新特性有:

  • 接口的默認方法
  • Lambda 表達式
  • 函數式接口
  • 方法與構造函數引用
  • 更好的類型推斷
  • Streams
  • Date API
  • Optional
  • Metaspace

感謝閱讀,都是根據自己理解寫的,有不對的地方歡迎各位大佬指正,也希望能幫助到更多的人。
注:(JVM篇)持續更新中
題目來自:https://blog.csdn.net/weixin_44946117/article/details/90607041

部分內容來自網絡整理,如果侵權請聯系刪除。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容