Java經典面試題答案解析(1-80題)

前言

前幾天,在茫茫的互聯網海洋中尋尋覓覓,把收藏的800道Java經典面試題都發出來,有小夥伴私聊我要答案。所以感覺沒有答案的面試題是沒有靈魂的,於是今天先整理基礎篇的前80道答案出來哈~

所有的Java面試題已經上傳github,答案也上傳了一部分~

https://github.com/whx123/JavaHome/tree/master/Java%E9%9D%A2%E8%AF%95%E9%A2%98%E9%9B%86%E7%BB%93%E5%8F%B7

Java 基礎

1. equals與==的區別

==

  • 如果是基本類型,==表示判斷它們值是否相等;

  • 如果是引用對象,==表示判斷兩個對象指向的內存地址是否相同。

equals

  • 如果是字符串,表示判斷字符串內容是否相同;

  • 如果是object對象的方法,比較的也是引用的內存地址值;

  • 如果自己的類重寫equals方法,可以自定義兩個對象是否相等。

2. final, finally, finalize 的區別

  • final 用於修飾屬性,方法和類, 分別表示屬性不能被重新賦值, 方法不可被覆蓋, 類不可被繼承.

  • finally 是異常處理語句結構的一部分,一般以ty-catch-finally出現,finally代碼塊表示總是被執行.

  • finalize 是Object類的一個方法,該方法一般由垃圾回收器來調用,當我們調用System.gc() 方法的時候,由垃圾回收器調用finalize()方法,回收垃圾,JVM並不保證此方法總被調用.

3. 重載和重寫的區別

  • 重寫必須繼承,重載不用。

  • 重載表示同一個類中可以有多個名稱相同的方法,但這些方法的參數列表各不相同(即參數個數或類型不同)

  • 重寫表示子類中的方法與父類中的某個方法的名稱和參數完全相同啦,通過子類實例對象調用這個方法時,將調用子類中的定義方法,這相當於把父類中定義的那個完全相同的方法給覆蓋了,這是面向對象編程的多態性的一種表現。

  • 重寫的方法修飾符大於等於父類的方法,即訪問權限只能比父類的更大,不能更小,而重載和修飾符無關。

  • 重寫覆蓋的方法中,只能比父類拋出更少的異常,或者是拋出父類拋出的異常的子異常,因爲不能坑爹啊哈哈~

4. 兩個對象的hashCode()相同,則 equals()是否也一定爲 true?

兩個對象equals相等,則它們的hashcode必須相等,如果兩個對象的hashCode()相同,則equals()不一定爲true。

hashCode 的常規協定:

  • 在 Java 應用程序執行期間,在對同一對象多次調用 hashCode 方法時,必須一致地返回相同的整數,前提是將對象進行 equals 比較時所用的信息沒有被修改。從某一應用程序的一次執行到同一應用程序的另一次執行,該整數無需保持一致。

  • 兩個對象的equals()相等,那麼對這兩個對象中的每個對象調用 hashCode 方法都必須生成相同的整數結果。

  • 兩個對象的equals()不相等,那麼對這兩個對象中的任一對象上調用 hashCode 方法不要求一定生成不同的整數結果。但是,爲不相等的對象生成不同整數結果可以提高哈希表的性能。

5. 抽象類和接口有什麼區別

  • 抽象類要被子類繼承,接口要被子類實現。

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

  • 抽象類中可以有普通成員變量,接口中沒有普通成員變量,它的變量只能是公共的靜態的常量

  • 一個類可以實現多個接口,但是隻能繼承一個父類,這個父類可以是抽象類。

  • 接口只能做方法聲明,抽象類中可以作方法聲明,也可以做方法實現。

  • 抽象級別(從高到低):接口>抽象類>實現類。

  • 抽象類主要是用來抽象類別,接口主要是用來抽象方法功能。

  • 抽象類的關鍵字是abstract,接口的關鍵字是interface

6. BIO、NIO、AIO 有什麼區別?

這個答案來自互聯網哈,個人覺得是最好理解的~

  • BIO:線程發起 IO 請求,不管內核是否準備好 IO 操作,從發起請求起,線程一直阻塞,直到操作完成。

  • NIO:線程發起 IO 請求,立即返回;內核在做好 IO 操作的準備之後,通過調用註冊的回調函數通知線程做 IO 操作,線程開始阻塞,直到操作完成。

  • AIO:線程發起 IO 請求,立即返回;內存做好 IO 操作的準備之後,做 IO 操作,直到操作完成或者失敗,通過調用註冊的回調函數通知線程做 IO 操作完成或者失敗。

BIO 是一個連接一個線程。,NIO 是一個請求一個線程。,AIO 是一個有效請求一個線程。

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

  • NIO:同步非阻塞,服務器實現模式爲一個請求一個線程,即客戶端發送的連接請求都會註冊到多路複用器上,多路複用器輪詢到連接有I/O請求時才啓動一個線程進行處理。

  • AIO:異步非阻塞,服務器實現模式爲一個有效請求一個線程,客戶端的 IO 請求都是由 OS 先完成了再通知服務器應用去啓動線程進行處理。

7. String,Stringbuffer,StringBuilder的區別

String:

  • String類是一個不可變的類,一旦創建就不可以修改。

  • String是final類,不能被繼承

  • String實現了equals()方法和hashCode()方法

StringBuffer:

  • 繼承自AbstractStringBuilder,是可變類。

  • StringBuffer是線程安全的

  • 可以通過append方法動態構造數據。

StringBuilder:

  • 繼承自AbstractStringBuilder,是可變類。

  • StringBuilder是非線性安全的。

  • 執行效率比StringBuffer高。

8. JAVA中的幾種基本數據類型是什麼,各自佔用多少字節呢

基本類型位數字節
int324
short162
long648
byte81
char162
float324
double648
boolean

對於boolean,官方文檔未明確定義,它依賴於 JVM 廠商的具體實現。邏輯上理解是佔用 1位,但是實際中會考慮計算機高效存儲因素

感興趣的小夥伴,可以去看官網

9. Comparator與Comparable有什麼區別?

在牛客網看到這道題的答案,覺得寫的最好~

鏈接:https://www.nowcoder.com/questionTerminal/99f7d1f4f8374e419a6d6924d35d9530 來源:牛客網

  • Comparable & Comparator 都是用來實現集合中元素的比較、排序的,只是 Comparable 是在集合內部定義的方法實現的排序,Comparator 是在集合外部實現的排序,所以,如想實現排序,就需要在集合外定義 Comparator 接口的方法或在集合內實現 Comparable 接口的方法。

  • Comparator位於包java.util下,而Comparable位於包 java.lang下。

  • Comparable 是一個對象本身就已經支持自比較所需要實現的接口(如 String、Integer 自己就可以完成比較大小操作,已經實現了Comparable接口) 自定義的類要在加入list容器中後能夠排序,可以實現Comparable接口,在用Collections類的sort方法排序時,如果不指定Comparator,那麼就以自然順序排序, 這裏的自然順序就是實現Comparable接口設定的排序方式。

  • 而 Comparator 是一個專用的比較器,當這個對象不支持自比較或者自比較函數不能滿足你的要求時,你可以寫一個比較器來完成兩個對象之間大小的比較。

  • 可以說一個是自已完成比較,一個是外部程序實現比較的差別而已。用 Comparator 是策略模式(strategy design pattern),就是不改變對象自身,而用一個策略對象(strategy object)來改變它的行爲。比如:你想對整數採用絕對值大小來排序,Integer 是不符合要求的,你不需要去修改 Integer 類(實際上你也不能這麼做)去改變它的排序行爲,只要使用一個實現了 Comparator 接口的對象來實現控制它的排序就行了。

10. String類能被繼承嗎,爲什麼。

首先,String是一個final修飾的類,final修飾的類不可以被繼承。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {

String類爲什麼不能被繼承呢?

有兩個原因:

  • 效率性,String 類作爲最常用的類之一,禁止被繼承和重寫,可以提高效率。

  • 安全性,String 類中有很多調用底層的本地方法,調用了操作系統的 API,如果方法可以重寫,可能被植入惡意代碼,破壞程序。

11. 說說Java中多態的實現原理

  • 多態機制包括靜態多態(編譯時多態)和動態多態(運行時多態)

  • 靜態多態比如說重載,動態多態一般指在運行時才能確定調用哪個方法。

  • 我們通常所說的多態一般指運行時多態,也就是編譯時不確定究竟調用哪個具體方法,一直等到運行時才能確定。

  • 多態實現方式:子類繼承父類(extends)和類實現接口(implements)

  • 多態核心之處就在於對父類方法的改寫或對接口方法的實現,以取得在運行時不同的執行效果。

  • Java 裏對象方法的調用是依靠類信息裏的方法表實現的,對象方法引用調用和接口方法引用調用的大致思想是一樣的。當調用對象的某個方法時,JVM查找該對象類的方法表以確定該方法的直接引用地址,有了地址後才真正調用該方法。

舉個例子吧,假設有個Fruit父類,一個taste味道方法,兩個子類Apple和Pear,如下:

abstract class Fruit {
    abstract String taste() ;
}
class Apple extends Fruit {
    @Override
    String taste() {
        return "酸酸的";
    }
}
class Pear extends Fruit {
    @Override
    String taste() {
        return "甜甜的";
    }
}
public class Test {
    public static void main(String[] args) {
        Fruit f = new Apple();
        System.out.println(f.taste());
    }
}

程序運行,當調用對象Fruit f的方法taste時,JVM查找Fruit對象類的方法表以確定taste方法的直接引用地址,到底來自Apple還是Pear,確定後才真正調用對應子類的taste方法,

12. Java泛型和類型擦除

這個面試題,可以看我這篇文章哈~

Java程序員必備基礎:泛型解析

13. int和Integer 有什麼區別,還有Integer緩存的實現

這裏考察3個知識點吧:

  • int 是基本數據類型,interger 是 int 的封裝類

  • int 默認值爲 0 ,而interger 默認值爲 null, Interger使用需要判空處理

  • Integer的緩存機制:爲了節省內存和提高性能,Integer類在內部通過使用相同的對象引用實現緩存和重用,Integer類默認在-128 ~ 127 之間,可以通過 -XX:AutoBoxCacheMax進行修改,且這種機制僅在自動裝箱的時候有用,在使用構造器創建Integer對象時無用。

看個Integer的緩存的例子,加深一下印象哈:

Integer a = 10;
Integer b = 10;
Integer c = 129;
Integer d = 129;
System.out.println(a == b);
System.out.println(c == d);
輸出結果:
true
false

14. 說說反射的用途及實現原理,Java獲取反射的三種方法

這道面試題,看我這篇文章哈:談談Java反射:從入門到實踐,再到原理

Java獲取反射的三種方法

  • 第一種,使用 Class.forName 靜態方法。

  • 第二種,使用類的.class 方法

  • 第三種,使用實例對象的 getClass() 方法。

15. 面向對象的特徵

面向對象的三大特徵:

  • 封裝

  • 繼承

  • 多態

16. &和&&的區別

  • 按位與, a&b 表示把a和b都轉換成二進制數,再進行與的運算;

  • &和&&都是邏輯運算符號,&&又叫短路運算符

  • 邏輯與,a&& b ,a&b 都表示當且僅當兩個操作數均爲 true時,其結果才爲 true,否則爲false。

  • 邏輯與跟短路與的差別是非常巨大的,雖然二者都要求運算符左右兩端的布爾值都是true,整個表達式的值纔是true。但是,&&之所以稱爲短路運算,是因爲如果&&左邊的表達式的值是false,右邊的表達式會被直接短路掉,不會進行運算。

17. Java中IO流分爲幾種?

  • Java中的流分爲兩種:一種是字節流,另一種是字符流。

  • IO流分別由四個抽象類來表示(兩輸入兩輸出):InputStream,OutputStream,Reader,Writer。

18. 講講類的實例化順序,比如父類靜態數據,構造函數,子類靜態數據,構造函數。

直接看個例子吧:

public class Parent {
    {
        System.out.println("父類非靜態代碼塊");
    }
    static {
        System.out.println("父類靜態塊");
    }
    public Parent() {
        System.out.println("父類構造器");
    }
}
public class Son extends Parent {
    public Son() {
        System.out.println("子類構造器");
    }
    static {
        System.out.println("子類靜態代碼塊");
    }
    {
        System.out.println("子類非靜態代碼塊");
    }
}
public class Test {
    public static void main(String[] args) {
        Son son = new Son();
    }
}

運行結果:

父類靜態塊
子類靜態代碼塊
父類非靜態代碼塊
父類構造器
子類非靜態代碼塊
子類構造器

所以,類實例化順序爲:父類靜態代碼塊/靜態域->子類靜態代碼塊/靜態域 -> 父類非靜態代碼塊 -> 父類構造器 -> 子類非靜態代碼塊 -> 子類構造器

19. Java創建對象有幾種方式

Java創建對象有5種方式

  • 用new語句創建對象。

  • 使用反射,使用Class.newInstance()創建對象/調用類對象的構造方法——Constructor

  • 調用對象的clone()方法。

  • 運用反序列化手段,調用java.io.ObjectInputStream對象的readObject()方法.

  • 使用Unsafe

20. 如何將GB2312編碼的字符串轉換爲ISO-8859-1編碼的字符串呢?

public class Test {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String str = "撿田螺的小男孩";
        String strIso = new String(str.getBytes("GB2312"), "ISO-8859-1");
        System.out.println(strIso);
    }
}

21. 守護線程是什麼?用什麼方法實現守護線程

  • 守護線程是運行在後臺的一種特殊進程。

  • 它獨立於控制終端並且週期性地執行某種任務或等待處理某些發生的事件。

  • 在 Java 中垃圾回收線程就是特殊的守護線程。

22. notify()和 notifyAll()有什麼區別?

  • notify是喚醒一個處於該對象wait的線程,而notifyAll是喚醒所有處於該對象wait的線程。

  • 但是喚醒不等於就能執行了,需要得到鎖對象纔能有權利繼續執行,而鎖只有一把,所以多個線程被喚醒時需要爭取該鎖。

23. Java語言是如何處理異常的,關鍵字throws、throw、try、catch、finally怎麼使用?

這道面試題,可以看我這篇文章哈:Java程序員必備:異常的十個關鍵知識點

24. 談談Java的異常層次結構

從前從前,有位老人,他的名字叫Throwable,他生了兩個兒子,大兒子叫Error,二兒子叫Exception

Error

表示編譯時或者系統錯誤,如虛擬機相關的錯誤,OutOfMemoryError等,error是無法處理的。

Exception

代碼異常,Java程序員關心的基類型通常是Exception。它能被程序本身可以處理,這也是它跟Error的區別。

它可以分爲RuntimeException(運行時異常)和CheckedException(可檢查的異常)。

常見的RuntimeException異常:

- NullPointerException 空指針異常
- ArithmeticException 出現異常的運算條件時,拋出此異常
- IndexOutOfBoundsException 數組索引越界異常
- ClassNotFoundException 找不到類異常
- IllegalArgumentException(非法參數異常)

常見的 Checked Exception 異常:

- IOException (操作輸入流和輸出流時可能出現的異常)
- ClassCastException(類型轉換異常類)
  • Checked Exception就是編譯器要求你必須處置的異常。

  • 與之相反的是,Unchecked Exceptions,它指編譯器不要求強制處置的異常,它包括Error和RuntimeException 以及他們的子類。

25. 靜態內部類與非靜態內部類有什麼區別

這道面試題,可以看我這篇文章哈:Java程序員必備基礎:內部類解析

  • 靜態內部類可以有靜態成員(方法,屬性),而非靜態內部類則不能有靜態成員(方法,屬性)。

  • 靜態內部類只能夠訪問外部類的靜態成員和靜態方法,而非靜態內部類則可以訪問外部類的所有成員(方法,屬性)。

  • 實例化靜態內部類與非靜態內部類的方式不同

  • 調用內部靜態類的方法或靜態變量,可以通過類名直接調用

26. String s與new String與有什麼區別

String str ="whx";
String newStr =new String ("whx");

String str ="whx"

先在常量池中查找有沒有"whx" 這個對象,如果有,就讓str指向那個"whx".如果沒有,在常量池中新建一個“whx”對象,並讓str指向在常量池中新建的對象"whx"。

String newStr =new String ("whx");

是在堆中建立的對象"whx" ,在棧中創建堆中"whx" 對象的內存地址。

如圖所示:

網上這篇文章講的挺好的:String和New String()的區別

27. 反射中,Class.forName和ClassLoader的區別

Class.forName和ClassLoader都可以對類進行加載。它們區別在哪裏呢?ClassLoader負責加載 Java 類的字節代碼到 Java 虛擬機中。Class.forName其實是調用了ClassLoader,如下:

這裏面,forName0的第二個參數爲true,表示對加載的類進行初始化化。其實還可以調用 Class<?>forName(Stringname,booleaninitialize,ClassLoaderloader)方法實現一樣的功能,它的源碼如下:

所以,Class.forName和ClassLoader的區別,就是在類加載的時候,class.forName有參數控制是否對類進行初始化。

28. JDK動態代理與cglib實現的區別

  • java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。

  • cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。

  • JDK動態代理只能對實現了接口的類生成代理,而不能針對類

  • cglib是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法。因爲是繼承,所以該類或方法最好不要聲明成final

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

Error: 表示編譯時或者系統錯誤,如虛擬機相關的錯誤,OutOfMemoryError等,error是無法處理的。

Exception: 代碼異常,Java程序員關心的基類型通常是Exception。它能被程序本身可以處理,這也是它跟Error的區別。

它可以分爲RuntimeException(運行時異常)和CheckedException(可檢查的異常)。常見的RuntimeException異常:

- NullPointerException 空指針異常
- ArithmeticException 出現異常的運算條件時,拋出此異常
- IndexOutOfBoundsException 數組索引越界異常
- ClassNotFoundException 找不到類異常
- IllegalArgumentException(非法參數異常)

常見的 Checked Exception 異常:

- IOException (操作輸入流和輸出流時可能出現的異常)
- ClassCastException(類型轉換異常類)

有興趣可以看我之前寫得這篇文章:Java程序員必備:異常的十個關鍵知識點

30. 深拷貝和淺拷貝區別

淺拷貝

複製了對象的引用地址,兩個對象指向同一個內存地址,所以修改其中任意的值,另一個值都會隨之變化。

深拷貝

將對象及值複製過來,兩個對象修改其中任意的值另一個值不會改變

31. JDK 和 JRE 有什麼區別?

  • JDK:Java Development Kit 的簡稱,Java 開發工具包,提供了 Java 的開發環境和運行環境。

  • JRE:Java Runtime Environment 的簡稱,Java 運行環境,爲 Java 的運行提供了所需環境。

32. String 類的常用方法都有那些呢?

  • indexOf():返回指定字符的索引。

  • charAt():返回指定索引處的字符。

  • replace():字符串替換。

  • trim():去除字符串兩端空白。

  • split():分割字符串,返回一個分割後的字符串數組。

  • getBytes():返回字符串的 byte 類型數組。

  • length():返回字符串長度。

  • toLowerCase():將字符串轉成小寫字母。

  • toUpperCase():將字符串轉成大寫字符。

  • substring():截取字符串。

  • equals():字符串比較。

33. 談談自定義註解的場景及實現

  • 之前我這邊有這麼一個業務場景,用Redis控制接口調用頻率,有使用過自定義註解。

  • 通過 AOP(動態代理機制)給方法添加切面,通過反射來獲取方法包含的註解,如果包含自定義關鍵字註解,就通過Redis進行校驗攔截請求。

有關於註解,建議大家看一下java編程思想的註解篇章哈~

34. 說說你熟悉的設計模式有哪些?

設計模式分爲三大類:

  • 創建型模式:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式(5種)

  • 結構型模式:適配器模式、裝飾者模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。(7種)

  • 行爲型模式:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。(11種)

最好平時積累一下,單例模式(7種實現方式),工廠模式,模板方法設計模式,策略模式,裝飾者模式、代理模式這幾種怎麼寫吧~

35. 抽象工廠和工廠方法模式的區別?

可以看一下這篇文章介紹:抽象工廠模式-與-工廠方法模式區別

36. 什麼是值傳遞和引用傳遞?

  • 值傳遞是對基本型變量而言的,傳遞的是該變量的一個副本,改變副本不影響原變量.

  • 引用傳遞一般是對於對象型變量而言的,傳遞的是該對象地址的一個副本, 並不是原對象本身 。所以對引用對象進行操作會同時改變原對象.

37. 可以在static環境中訪問非static變量嗎?

static變量在Java中是屬於類的,它在所有的實例中的值是一樣的。當類被Java虛擬機載入的時候,會對static變量進行初始化。因爲靜態的成員屬於類,隨着類的加載而加載到靜態方法區內存,當類加載時,此時不一定有實例創建,沒有實例,就不可以訪問非靜態的成員。類的加載先於實例的創建,因此靜態環境中,不可以訪問非靜態!

38. Java支持多繼承麼,爲什麼?

不支持多繼承,原因:

  • 安全性的考慮,如果子類繼承的多個父類裏面有相同的方法或者屬性,子類將不知道具體要繼承哪個。

  • Java提供了接口和內部類以達到實現多繼承功能,彌補單繼承的缺陷。

39. 用最有效率的方法計算2乘以8?

2 << 3
  • 將一個數左移n位,就相當於這個數乘以了2的n次方。

  • 那麼,一個數乘以8只要將其左移3位即可。

  • 而cpu直接支持位移運算,且效率最高。

40. 構造器是否可被重寫?

構造器是不能被繼承的,因爲每個類的類名都不相同,而構造器名稱與類名相同,所以談不上繼承。又由於構造器不能被繼承,所以相應的就不能被重寫了。

41. char型變量中能不能存貯一箇中文漢字,爲什麼?

在Java中,char類型佔2個字節,而且Java默認採用Unicode編碼,一個Unicode碼是16位,所以一個Unicode碼佔兩個字節,Java中無論漢子還是英文字母都是用Unicode編碼來表示的。所以,在Java中,char類型變量可以存儲一箇中文漢字。

char ch = '啦';
System.out.println("char:" + ch);

42. 如何實現對象克隆?

  • 實現 Cloneable 接口,重寫 clone() 方法。

  • Object 的 clone() 方法是淺拷貝,即如果類中屬性有自定義引用類型,只拷貝引用,不拷貝引用指向的對象。

  • 對象的屬性的Class 也實現 Cloneable 接口,在克隆對象時也手動克隆屬性,完成深拷貝

  • 結合序列化(JDK java.io.Serializable 接口、JSON格式、XML格式等),完成深拷貝

43. object中定義了哪些方法?

  • getClass(); 獲取類結構信息

  • hashCode() 獲取哈希碼

  • equals(Object) 默認比較對象的地址值是否相等,子類可以重寫比較規則

  • clone() 用於對象克隆

  • toString() 把對象轉變成字符串

  • notify() 多線程中喚醒功能

  • notifyAll() 多線程中喚醒所有等待線程的功能

  • wait() 讓持有對象鎖的線程進入等待

  • wait(long timeout) 讓持有對象鎖的線程進入等待,設置超時毫秒數時間

  • wait(long timeout, int nanos) 讓持有對象鎖的線程進入等待,設置超時納秒數時間

  • finalize() 垃圾回收前執行的方法

44. hashCode的作用是什麼?

  • hashCode的存在主要是用於查找的快捷性,如Hashtable,HashMap等,hashCode是用來在散列存儲結構中確定對象的存儲地址的;

  • 如果兩個對象相同,就是適用於equals(java.lang.Object) 方法,那麼這兩個對象的hashCode一定要相同;

  • 如果對象的equals方法被重寫,那麼對象的hashCode也儘量重寫,並且產生hashCode使用的對象,一定要和equals方法中使用的一致,否則就會違反上面提到的第2點;

  • 兩個對象的hashCode相同,並不一定表示兩個對象就相同,也就是不一定適用於equals(java.lang.Object) 方法,只能夠說明這兩個對象在散列存儲結構中.

45. for-each與常規for循環的效率對比

關於這個問題,《Effective Java》給我們做的解答:

for-each能夠讓代碼更加清晰,並且減少了出錯的機會。下面的慣用代碼適用於集合與數組類型:

for (Element e : elements) {
     doSomething(e); 
}

使用for-each循環與常規的for循環相比,並不存在性能損失,即使對數組進行迭代也是如此。實際上,在有些場合下它還能帶來微小的性能提升,因爲它只計算一次數組索引的上限。

46. 寫出幾種單例模式實現,懶漢模式和餓漢模式區別

7種:

  • 第一種(懶漢,線程不安全)

  • 第二種(懶漢,線程安全)

  • 第三種(餓漢)

  • 第四種(餓漢,變種)

  • 第五種(靜態內部類)

  • 第六種(枚舉):

  • 第七種(雙重校驗鎖)

可以看這篇文章:單例模式的七種寫法

47. 請列出 5 個運行時異常。

- NullPointerException 空指針異常
- ArithmeticException 出現異常的運算條件時,拋出此異常
- IndexOutOfBoundsException 數組索引越界異常
- ClassNotFoundException 找不到類異常
- IllegalArgumentException(非法參數異常)

48. 2個不相等的對象有可能具有相同的 hashcode嗎?

有可能哈~

hashCode 的常規協定:

  • 在 Java 應用程序執行期間,在對同一對象多次調用 hashCode 方法時,必須一致地返回相同的整數,前提是將對象進行 equals 比較時所用的信息沒有被修改。從某一應用程序的一次執行到同一應用程序的另一次執行,該整數無需保持一致。

  • 兩個對象的equals()相等,那麼對這兩個對象中的每個對象調用 hashCode 方法都必須生成相同的整數結果。

  • 兩個對象的equals()不相等,那麼對這兩個對象中的任一對象上調用 hashCode 方法不要求一定生成不同的整數結果。但是,爲不相等的對象生成不同整數結果可以提高哈希表的性能。

49. 訪問修飾符public,private,protected,以及default的區別?

50. 談談final在java中的作用?

  • final 修飾的類叫最終類,該類不能被繼承。

  • final 修飾的方法不能被重寫。

  • final 修飾的變量叫常量,常量必須初始化,初始化之後值就不能被修改。

51. java中的Math.round(-1.5) 等於多少呢?

JDK 中的 java.lang.Math 類:

  • round() :返回四捨五入,負 .5 小數返回較大整數,如 -1.5 返回 -1。

  • ceil() :返回小數所在兩整數間的較大值,如 -1.5 返回 -1.0。

  • floor() :返回小數所在兩整數間的較小值,如 -1.5 返回 -2.0。

52. String屬於基礎的數據類型嗎?

String 不屬於基礎類型,基礎類型有 8 種:byte、boolean、char、short、int、float、long、double,而 String 屬於對象。

53. 如何將字符串反轉呢?

  • 使用 StringBuilder 或 StringBuffer 的 reverse 方法,本質都調用了它們的父類 AbstractStringBuilder 的 reverse 方法實現。(JDK1.8)

  • 使用chatAt函數,倒過來輸出;

54. 描述動態代理的幾種實現方式,它們分別有什麼優缺點

  • JDK動態代理

  • CGLIB動態代理

  • JDK原聲動態代理時java原聲支持的、不需要任何外部依賴、但是它只能基於接口進行代理

  • CGLIB通過繼承的方式進行代理、無論目標對象沒有沒實現接口都可以代理,但是無法處理final的情況

55. 在自己的代碼中,如果創建一個java.lang.String類,這個類是否可以被類加載器加載?爲什麼。

不可以。因爲JDK處於安全性的考慮,基於雙親委派模型,優先加載JDK的String類,如果java.lang.String已經加載,便不會再次被加載。

56. 談談你對java.lang.Object對象中hashCode和equals方法的理解。在什麼場景下需要重新實現這兩個方法。

  • 在我們的業務系統中判斷對象時有時候需要的不是一種嚴格意義上的相等,而是一種業務上的對象相等。在這種情況下,原生的equals方法就不能滿足我們的需求了,所以這個時候我們需要重寫equals方法,來滿足我們的業務系統上的需求。

  • 那麼爲什麼在重寫equals方法的時候需要重寫hashCode方法呢?如果只重寫了equals方法而沒有重寫hashCode方法的話,則會違反約定的第二條:相等的對象必須具有相等的散列碼.所以hashCode和equals方法都需要重寫

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

Java 泛型(generics)是 JDK 5 中引入的一個新特性,其本質是參數化類型,解決不確定具體對象類型的問題。

這個面試題,可以看我這篇文章哈~Java程序員必備基礎:泛型解析

58. 什麼是序列化,怎麼序列化,反序列呢?

  • 序列化:把Java對象轉換爲字節序列的過程

  • 反序列:把字節序列恢復爲Java對象的過程 

可以看我這篇文章哈~ Java程序員必備:序列化全方位解析

59. java8的新特性。

  • Lambda 表達式:Lambda允許把函數作爲一個方法的參數

  • Stream API :新添加的Stream API(java.util.stream) 把真正的函數式編程風格引入到Java中

  • 方法引用:方法引用提供了非常有用的語法,可以直接引用已有Java類或對象(實例)的方法或構造器。

  • 默認方法:默認方法就是一個在接口裏面有了一個實現的方法。

  • Optional 類 :Optional 類已經成爲 Java 8 類庫的一部分,用來解決空指針異常。

  • Date Time API :加強對日期與時間的處理。

60. 匿名內部類是什麼?如何訪問在其外面定義的變量呢?

匿名內部類就是沒有名字的內部類,日常開發中使用的比較多。

public class Outer {
    private void test(final int i) {
        new Service() {
            public void method() {
                for (int j = 0; j < i; j++) {
                    System.out.println("匿名內部類" );
                }
            }
        }.method();
    }
 }
 //匿名內部類必須繼承或實現一個已有的接口
 interface Service{
    void method();
}

匿名內部類還有以下特點:

  • 匿名內部類沒有名字的

  • 匿名內部類必須繼承一個抽象類或者實現一個接口。

  • 匿名內部類不能定義任何靜態成員和靜態方法。

  • 當所在的方法的形參需要被匿名內部類使用時,必須聲明爲 final。

  • 匿名內部類不能是抽象的,它必須要實現繼承的類或者實現的接口的所有抽象方法。

  • 匿名內部類不能訪問外部類方法中的局部變量,除非該變量被聲明爲final類型

可以看我這篇文章哈~Java程序員必備基礎:內部類解析

61. break和continue有什麼區別?

  • break可以使流程跳出switch語句體,也可以在循環結構終止本層循環體,從而提前結束本層循環。

  • continue的作用是跳過本次循環體中餘下尚未執行的語句,立即進行下一次的循環條件判定,可以理解爲僅結束本次循環

62. String s = "Hello";s = s + " world!";這兩行代碼執行後,原始的 String 對象中的內容是否會改變?

沒有。因爲 String 被設計成不可變(immutable)類,所以它的所有對象都是不可變對象。

63. String s="a"+"b"+"c"+"d";創建了幾個對象?

1個而已啦。

Java 編譯器對字符串常量直接相加的表達式進行優化,不等到運行期去進行加法運算,在編譯時就去掉了加號,直接將其編譯成一個這些常量相連的結果。所以 "a"+"b"+"c"+"d" 相當於直接定義一個 "abcd" 的字符串。

64. try-catch-finally-return執行順序

try-catch-finally-return 執行描述:

  • 如果不發生異常,不會執行catch部分。

  • 不管有沒有發生異常,finally都會執行到。

  • 即使try和catch中有return時,finally仍然會執行

  • finally是在return後面的表達式運算完後再執行的。(此時並沒有返回運算後的值,而是先把要返回的值保存起來,若finally中無return,則不管finally中的代碼怎麼樣,返回的值都不會改變,仍然是之前保存的值),該情況下函數返回值是在finally執行前確定的)

  • finally部分就不要return了,要不然,就回不去try或者catch的return了。

看一個例子

 public static void main(String[] args) throws IOException {
        System.out.println("result:" + test());
    }
    private static int test() {
        int temp = 1;
        try {
            System.out.println("start execute try,temp is:"+temp);
            return ++temp;
        } catch (Exception e) {
            System.out.println("start execute catch temp is: "+temp);
            return ++temp;
        } finally {
            System.out.println("start execute finally,temp is:" + temp);
            ++temp;
        }
    }

運行結果:

start execute try,temp is:1
start execute finally,temp is:2
result:2

分析:

  • 先執行try部分,輸出日誌,執行 ++temp表達式,temp變爲2,這個值被保存起來。

  • 因爲沒有發生異常,所以catch代碼塊跳過。

  • 執行finally代碼塊,輸出日誌,執行 ++temp表達式.

  • 返回try部分保存的值2.

65. Java 7新的 try-with-resources語句,平時有使用嗎

try-with-resources,是Java7提供的一個新功能,它用於自動資源管理。

  • 資源是指在程序用完了之後必須要關閉的對象。

  • try-with-resources保證了每個聲明瞭的資源在語句結束的時候會被關閉

  • 什麼樣的對象才能當做資源使用呢?只要實現了java.lang.AutoCloseable接口或者java.io.Closeable接口的對象,都OK。

try-with-resources出現之前

try{
    //open resources like File, Database connection, Sockets etc
} catch (FileNotFoundException e) {
    // Exception handling like FileNotFoundException, IOException etc
}finally{
    // close resources
}

Java7, try-with-resources出現之後,使用資源實現

try(// open resources here){
    // use resources
} catch (FileNotFoundException e) {
    // exception handling
}
// resources are closed as soon as try-catch block is executed.

Java7使用資源demo

public class Java7TryResourceTest {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader(
                "C:/jaywei.txt"))) {
            System.out.println(br.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用了 try-with-resources的好處

  • 代碼更加優雅,行數更少。

  • 資源自動管理,不用擔心內存泄漏問題。

66. 簡述一下面向對象的”六原則一法則”。

  • 單一職責原則:一個類只做它該做的事情。

  • 開閉原則:軟件實體應當對擴展開放,對修改關閉。

  • 依賴倒轉原則:面向接口編程。

  • 接口隔離原則:接口要小而專,絕不能大而全。

  • 合成聚合複用原則:優先使用聚合或合成關係複用代碼。

  • 迪米特法則:迪米特法則又叫最少知識原則,一個對象應當對其他對象有儘可能少的瞭解。

67. switch是否能作用在byte 上,是否能作用在long 上,是否能作用在String上?

  • switch可作用於char byte short int

  • switch可作用於char byte short int對應的包裝類

  • switch不可作用於long double float boolean,以及他們的包裝類

68. 數組有沒有length()方法?String有沒有length()方法?

  • 數組沒有length()方法,而是length;

  • String有length()方法

69. 是否可以從一個靜態(static)方法內部發出對非靜態(non-static)方法的調用?

不可以。

  • 非static方法是要與對象實例息息相關的,必須在創建一個對象後,纔可以在該對象上進行非static方法調用,而static方法跟類相關的,不需要創建對象,可以由類直接調用。

  • 當一個static方法被調用時,可能還沒有創建任何實例對象,如果從一個static方法中發出對非static方法的調用,那個非static方法是關聯到哪個對象上的呢?這個邏輯是不成立的

  • 因此,一個static方法內部不可以發出對非static方法的調用。

70. String s = new String("jay");創建了幾個字符串對象?

一個或兩個

  • 第一次調用 new String("jay"); 時,會在堆內存中創建一個字符串對象,同時在字符串常量池中創建一個對象 "jay"

  • 第二次調用 new String("jay"); 時,只會在堆內存中創建一個字符串對象,指向之前在字符串常量池中創建的 "jay"

可以看老王這篇文章,很清晰~別再問我 new 字符串創建了幾個對象了!我來證明給你看!

71. this和super關鍵字的作用

this:

  • 對象內部指代自身的引用

  • 解決成員變量和局部變量同名問題

  • 可以調用成員變量,不能調用局部變量

  • 可以調用成員方法

  • 在普通方法中可以省略 this

  • 在靜態方法當中不允許出現 this 關鍵字

super:

  • 調用父類 的成員或者方法

  • 調用父類的構造函數

72. 我們能將int強制轉換爲 byte類型的變量嗎?如果該值大於byte 類型的範圍,將會出現什麼現象?

可以,我們可以做強制轉換,但是在Java中,int是32位,byte是8位,如果強制做轉化,int類型的高24位將會被丟棄。

public class Test {
    public static void main(String[] args)  {
        int a =129;
        byte b = (byte) a;
        System.out.println(b);
        int c =10;
        byte d = (byte) c;
        System.out.println(d);
    }
}
輸出:
-127
10

73. float f=3.4;正確嗎?

不正確,精度不準確,應該用強制類型轉換

74. 接口可否繼承接口?抽象類是否可實現接口?抽象類是否可繼承實體類?

都可以的

75. Reader和InputStream區別?

  • InputStream是表示字節輸入流的所有類的超類

  • Reader是用於讀取字符流的抽象類

76. 列舉出JAVA中6個比較常用的包

  • java.lang;

  • java.util;

  • java.io;

  • java.sql;

  • java.awt;

  • java.net;

77. JDK 7有哪些新特性

  • Try-with-resource語句

  • NIO2 文件處理Files

  • switch可以支持字符串判斷條件

  • 泛型推導

  • 多異常統一處理

78. 同步和異步有什麼區別?

  • 同步,可以理解爲在執行完一個函數或方法之後,一直等待系統返回值或消息,這時程序是出於阻塞的,只有接收到返回的值或消息後才往下執行其他的命令。

  • 異步,執行完函數或方法後,不必阻塞性地等待返回值或消息,只需要向系統委託一個異步過程,那麼當系統接收到返回值或消息時,系統會自動觸發委託的異步過程,從而完成一個完整的流程。

  • 同步,就是實時處理(如打電話)

  • 異步,就是分時處理(如收發短信)

參考這篇文章~ 同步和異步的區別

79. 實際開發中,Java一般使用什麼數據類型來代表價格?

java中使用BigDecimal來表示價格是比較好的。

可以看這篇文章,寫得非常好老大說:誰要再用double定義商品金額,就自己收拾東西走

80. 64 位 JVM 中,int 的長度是多數?

int數據類型佔4個字節 32位,跟JVM位數沒關係的

公衆號

  • 歡迎關注我個人公衆號,交個朋友,一起學習哈~

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