2021年最新Java面試題及答案整理 --- 基礎篇(二)

1. try {}裏有一個return語句,那麼緊跟在這個try後的finally{}裏的code會不會被執行,何時被執行,在return前仍是後?

咱們知道finally{}中的語句是必定會執行的,那麼這個可能正常脫口而出就是return以前,return以後可能就出了這個方法了,鬼知道跑哪裏去了,但更準確的應該是在return中間執行,請看下面程序代碼的運行結果:java

public classTest {
    public static void main(String[]args) {
       System.out.println(newTest().test());;
    }
    static int test()
    {
       intx = 1;
       try
       {
          return x;
       }
       finally
       {
          ++x;
       }
    }
}

執行結果以下:mysql

1

運行結果是1,爲何呢?主函數調用子函數並獲得結果的過程,比如主函數準備一個空罐子,當子函數要返回結果時,先把結果放在罐子裏,而後再將程序邏輯返回到主函數。所謂返回,就是子函數說,我不運行了,你主函數繼續運行吧,這沒什麼結果可言,結果是在說這話以前放進罐子裏的。面試

22. 運行時異常與通常異常有何異同?

異常表示程序運行過程當中可能出現的非正常狀態,運行時異常表示虛擬機的一般操做中可能遇到的異常,是一種常見運行錯誤。java編譯器要求方法必須聲明拋出可能發生的非運行時異常,可是並不要求必須聲明拋出未被捕獲的運行時異常。算法

24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...

23. error和exception有什麼區別?

error 表示恢復不是不可能但很困難的狀況下的一種嚴重問題。好比說內存溢出。不可能期望程序能處理這樣的狀況。exception表示一種設計或實現問題。也就是說,它表示若是程序運行正常,從不會發生的狀況。sql

24. 簡單說說Java中的異常處理機制的簡單原理和應用。

異常是指java程序運行時(非編譯)所發生的非正常狀況或錯誤,與現實生活中的事件很類似,現實生活中的事件能夠包含事件發生的時間、地點、人物、情節等信息,能夠用一個對象來表示,Java使用面向對象的方式來處理異常,它把程序中發生的每一個異常也都分別封裝到一個對象來表示的,該對象中包含有異常的信息。編程

Java對異常進行了分類,不一樣類型的異常分別用不一樣的Java類表示,全部異常的根類爲java.lang.Throwable。數組

Throwable下面又派生了兩個子類:緩存

  • Error和Exception,Error表示應用程序自己沒法克服和恢復的一種嚴重問題,程序只有奔潰了,例如,說內存溢出和線程死鎖等系統問題。
  • Exception表示程序還可以克服和恢復的問題,其中又分爲系統異常和普通異常:

系統異常是軟件自己缺陷所致使的問題,也就是軟件開發人員考慮不周所致使的問題,軟件使用者沒法克服和恢復這種問題,但在這種問題下還可讓軟件系統繼續運行或者讓軟件掛掉,例如,數組腳本越界(ArrayIndexOutOfBoundsException),空指針異常(NullPointerException)、類轉換異常(ClassCastException);安全

普通異常是運行環境的變化或異常所致使的問題,是用戶可以克服的問題,例如,網絡斷線,硬盤空間不夠,發生這樣的異常後,程序不該該死掉。服務器

java爲系統異常和普通異常提供了不一樣的解決方案,編譯器強制普通異常必須try..catch處理或用throws聲明繼續拋給上層調用方法處理,因此普通異常也稱爲checked異常,而系統異常能夠處理也能夠不處理,因此,編譯器不強制用try..catch處理或用throws聲明,因此係統異常也稱爲unchecked異常。

25. == 和 equals 的區別是什麼?

"=="

對於基本類型和引用類型 == 的做用效果是不一樣的,以下所示:

  • 基本類型:比較的是值是否相同;
  • 引用類型:比較的是引用是否相同;
String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true
由於 x 和 y 指向的是同一個引用,因此 == 也是 true,而 new String()方法則重寫開闢了內存空間,因此 == 結果爲 false,而 equals 比較的一直是值,因此結果都爲 true。

equals

equals 本質上就是 ==,只不過 String 和 Integer 等重寫了 equals 方法,把它變成了值比較。看下面的代碼就明白了。

首先來看默認狀況下 equals 比較一個有相同值的對象,代碼以下:

class Cat {
    public Cat(String name) {
        this.name = name;
    }

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Cat c1 = new Cat("葉痕秋");
Cat c2 = new Cat("葉痕秋");
System.out.println(c1.equals(c2)); // false

輸出結果出乎咱們的意料,居然是 false?這是怎麼回事,看了 equals 源碼就知道了,源碼以下:

public boolean equals(Object obj) {
        return (this == obj);
}

原來 equals 本質上就是 ==。

那問題來了,兩個相同值的 String 對象,爲何返回的是 true?代碼以下:

String s1 = new String("葉子");
String s2 = new String("葉子");
System.out.println(s1.equals(s2)); // true

一樣的,當咱們進入 String 的 equals 方法,找到了答案,代碼以下:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

原來是 String 重寫了 Object 的 equals 方法,把引用比較改爲了值比較。

總結

== 對於基本類型來講是值比較,對於引用類型來講是比較的是引用;而 equals 默認狀況下是引用比較,只是不少類從新了 equals 方法,好比 String、Integer 等把它變成了值比較,因此通常狀況下 equals 比較的是值是否相等。

26. Hashcode的做用

java的集合有兩類,一類是List,還有一類是Set。前者有序可重複,後者無序不重複。當咱們在set中插入的時候怎麼判斷是否已經存在該元素呢,能夠經過equals方法。可是若是元素太多,用這樣的方法就會比較滿。

因而有人發明了哈希算法來提升集合中查找元素的效率。 這種方式將集合分紅若干個存儲區域,每一個對象能夠計算出一個哈希碼,能夠將哈希碼分組,每組分別對應某個存儲區域,根據一個對象的哈希碼就能夠肯定該對象應該存儲的那個區域。

hashCode方法能夠這樣理解:它返回的就是根據對象的內存地址換算出的一個值。這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode方法,就一會兒能定位到它應該放置的物理位置上。若是這個位置上沒有元素,它就能夠直接存儲在這個位置上,不用再進行任何比較了;若是這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址。這樣一來實際調用equals方法的次數就大大下降了,幾乎只須要一兩次。

24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...

27. 兩個對象的 hashCode() 相同, 那麼 equals() 也必定爲 true嗎?

不對,兩個對象的 hashCode() 相同,equals() 不必定 true。

代碼示例:

String str1 = "keep";
String str2 = "brother";
System. out. println(String. format("str1:%d | str2:%d",  str1. hashCode(),str2. hashCode()));
System. out. println(str1. equals(str2));

執行結果:

str1:1179395 | str2:1179395

false

代碼解讀:很顯然「keep」和「brother」的 hashCode() 相同,然而 equals() 則爲 false,由於在散列表中,hashCode() 相等即兩個鍵值對的哈希值相等,然而哈希值相等,並不必定能得出鍵值對相等。

28. 泛型經常使用特色

泛型是Java SE 1.5以後的特性, 《Java 核心技術》中對泛型的定義是:

「泛型」 意味着編寫的代碼能夠被不一樣類型的對象所重用。

「泛型」,顧名思義,「泛指的類型」。咱們提供了泛指的概念,但具體執行的時候卻能夠有具體的規則來約束,好比咱們用的很是多的ArrayList就是個泛型類,ArrayList做爲集合能夠存放各類元素,如Integer, String,自定義的各類類型等,但在咱們使用的時候經過具體的規則來約束,如咱們能夠約束集合中只存放Integer類型的元素,如

List<Integer> iniData = new ArrayList<>()

使用泛型的好處?

以集合來舉例,使用泛型的好處是咱們沒必要由於添加元素類型的不一樣而定義不一樣類型的集合,如整型集合類,浮點型集合類,字符串集合類,咱們能夠定義一個集合來存放整型、浮點型,字符串型數據,而這並非最重要的,由於咱們只要把底層存儲設置了Object便可,添加的數據所有均可向上轉型爲Object。 更重要的是咱們能夠經過規則按照本身的想法控制存儲的數據類型。

29. 面向對象的特徵

面向對象的編程語言有封裝、繼承 、抽象、多態等4個主要的特徵。

  1. 封裝: 把描述一個對象的屬性和行爲的代碼封裝在一個模塊中,也就是一個類中,屬性用變量定義,行爲用方法進行定義,方法能夠直接訪問同一個對象中的屬性。
  2. 抽象: 把現實生活中的對象抽象爲類。分爲過程抽象和數據抽象
  • 數據抽象 -->鳥有翅膀,羽毛等(類的屬性)
  • 過程抽象 -->鳥會飛,會叫(類的方法)
  1. 繼承:子類繼承父類的特徵和行爲。子類能夠有父類的方法,屬性(非private)。子類也能夠對父類進行擴展,也能夠重寫父類的方法。缺點就是提升代碼之間的耦合性。
  2. 多態: 多態是指程序中定義的引用變量所指向的具體類型和經過該引用變量發出的方法調用在編程時並不肯定,而是在程序運行期間才肯定(好比:向上轉型,只有運行才能肯定其對象屬性)。方法覆蓋和重載體現了多態性。

30. Java多態的理解

  1. 多態是繼封裝、繼承以後,面向對象的第三大特性。
  2. 多態現實意義理解:
  • 現實事物常常會體現出多種形態,如學生,學生是人的一種,則一個具體的同窗張三既是學生也是人,即出現兩種形態。
  • Java做爲面向對象的語言,一樣能夠描述一個事物的多種形態。如Student類繼承了Person類,一個Student的對象便既是Student,又是Person。
  1. 多態體現爲父類引用變量能夠指向子類對象。
  2. 前提條件:必須有子父類關係。

注意:在使用多態後的父類引用變量調用方法時,會調用子類重寫後的方法。

  1. 多態的定義與使用格式

定義格式:父類類型 變量名=new 子類類型();

31. 重載和重寫的區別

重寫(Override)

從字面上看,重寫就是 從新寫一遍的意思。其實就是在子類中把父類自己有的方法從新寫一遍。子類繼承了父類原有的方法,但有時子類並不想原封不動的繼承父類中的某個方法,因此在方法名,參數列表,返回類型(除過子類中方法的返回值是父類中方法返回值的子類時)都相同的狀況下, 對方法體進行修改或重寫,這就是重寫。但要注意子類函數的訪問修飾權限不能少於父類的。

public class Father {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Son s = new Son();
        s.sayHello();
    }

    public void sayHello() {
        System.out.println("Hello");
    }
}

class Son extends Father{

    @Override
    public void sayHello() {
        // TODO Auto-generated method stub
        System.out.println("hello by ");
    }
}

重寫 總結:

1.發生在父類與子類之間

2.方法名,參數列表,返回類型(除過子類中方法的返回類型是父類中返回類型的子類)必須相同

3.訪問修飾符的限制必定要大於被重寫方法的訪問修飾符(public>protected>default>private)

4.重寫方法必定不能拋出新的檢查異常或者比被重寫方法申明更加寬泛的檢查型異常

重載(Overload)

在一個類中,同名的方法若是有不一樣的參數列表(參數類型不一樣、參數個數不一樣甚至是參數順序不一樣)則視爲重載。同時,重載對返回類型沒有要求,能夠相同也能夠不一樣,但不能經過返回類型是否相同來判斷重載

public class Father {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Father s = new Father();
        s.sayHello();
        s.sayHello("wintershii");

    }

    public void sayHello() {
        System.out.println("Hello");
    }

    public void sayHello(String name) {
        System.out.println("Hello" + " " + name);
    }
}

重載 總結:

1.重載Overload是一個類中多態性的一種表現

2.重載要求同名方法的參數列表不一樣(參數類型,參數個數甚至是參數順序)

3.重載的時候,返回值類型能夠相同也能夠不相同。沒法以返回型別做爲重載函數的區分標準

24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...

33. Java建立對象有幾種方式?

java中提供瞭如下四種建立對象的方式:

  • new建立新對象
  • 經過反射機制
  • 採用clone機制
  • 經過序列化機制

34. ConcurrentModificationException異常出現的緣由

public class Test {
    public static void main(String[] args)  {
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(2);
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            Integer integer = iterator.next();
            if(integer==2)
                list.remove(integer);
        }
    }
}

執行上段代碼是有問題的,會拋出ConcurrentModificationException異常。

緣由:調用list.remove()方法致使modCountexpectedModCount的值不一致。

final void checkForComodification() {
    if (modCount != expectedModCount)
    throw new ConcurrentModificationException();
}

解決辦法:在迭代器中若是要刪除元素的話,須要調用Iterator類的remove方法。

public class Test {
    public static void main(String[] args)  {
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(2);
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            Integer integer = iterator.next();
            if(integer==2)
                iterator.remove();   //注意這個地方
        }
    }
}

35. HashMap和HashTable、ConcurrentHashMap區別?

相同點:

  1. HashMap和Hashtable都實現了Map接口
  2. 均可以存儲key-value數據

不一樣點:

  1. HashMap能夠把null做爲key或value,HashTable不能夠
  2. HashMap線程不安全,效率高。HashTable線程安全,效率低。
  3. HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。
什麼是fail-fast?
就是最快的時間能把錯誤拋出而不是讓程序執行。

36. 如何保證線程安全又效率高?

Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴展性更好。

ConcurrentHashMap將整個Map分爲N個segment(相似HashTable),能夠提供相同的線程安全,可是效率提高N倍,默認N爲16。

37. 咱們可否讓HashMap同步?

HashMap能夠經過下面的語句進行同步:

Map m = Collections.synchronizeMap(hashMap);

38. Java 中 IO 流分爲幾種?

按功能來分:輸入流(input)、輸出流(output)。

按類型來分:字節流和字符流。

字節流和字符流的區別是:字節流按 8 位傳輸以字節爲單位輸入輸出數據,字符流按 16 位傳輸以字符爲單位輸入輸出數據。

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

  • BIO:Block IO 同步阻塞式 IO,就是咱們日常使用的傳統 IO,它的特色是模式簡單使用方便,併發處理能力低。
  • NIO:Non IO 同步非阻塞 IO,是傳統 IO 的升級,客戶端和服務器端經過 Channel(通道)通信,實現了多路複用。
  • AIO:Asynchronous IO 是 NIO 的升級,也叫 NIO2,實現了異步非堵塞 IO ,異步 IO 的操做基於事件和回調機制。

40. Files的經常使用方法都有哪些?

  • Files. exists():檢測文件路徑是否存在。
  • Files. createFile():建立文件。
  • Files. createDirectory():建立文件夾。
  • Files. delete():刪除一個文件或目錄。
  • Files. copy():複製文件。
  • Files. move():移動文件。
  • Files. size():查看文件個數。
  • Files. read():讀取文件。
  • Files. write():寫入文件。

41. Java反射的做用於原理

一、定義:

反射機制是在運行時,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意個對象,都可以調用它的任意一個方法。在java中,只要給定類的名字,就能夠經過反射機制來得到類的全部信息。

這種動態獲取的信息以及動態調用對象的方法的功能稱爲Java語言的反射機制。

二、哪裏會用到反射機制?

jdbc就是典型的反射

Class.forName('com.mysql.jdbc.Driver.class');//加載MySQL的驅動類

這就是反射。如hibernate,struts等框架使用反射實現的。

24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...

42. 反射的實現方式

第一步:獲取Class對象,有4種方法: 1)Class.forName(「類的路徑」); 2)類名.class 3)對象名.getClass() 4)基本類型的包裝類,能夠調用包裝類的Type屬性來得到該包裝類的Class對象

43. 實現Java反射的類:

1)Class:表示正在運行的Java應用程序中的類和接口 注意: 全部獲取對象的信息都須要Class類來實現。 2)Field:提供有關類和接口的屬性信息,以及對它的動態訪問權限。 3)Constructor:提供關於類的單個構造方法的信息以及它的訪問權限 4)Method:提供類或接口中某個方法的信息

44. 反射機制的優缺點:

優勢:

一、可以運行時動態獲取類的實例,提升靈活性;

二、與動態編譯結合

缺點:

一、使用反射性能較低,須要解析字節碼,將內存中的對象進行解析。

解決方案:

​ 一、經過setAccessible(true)關閉JDK的安全檢查來提高反射速度;

​ 二、屢次建立一個類的實例時,有緩存會快不少

​ 三、ReflectASM工具類,經過字節碼生成的方式加快反射速度

二、相對不安全,破壞了封裝性(由於經過反射能夠得到私有方法和屬性)

45. Java 中 IO 流分爲幾種?

  • 按照流的流向分,能夠分爲輸入流和輸出流;
  • 按照操做單元劃分,能夠劃分爲字節流和字符流;
  • 按照流的角色劃分爲節點流和處理流。

Java Io 流共涉及 40 多個類,這些類看上去很雜亂,但實際上頗有規則,並且彼此之間存在很是緊密的聯繫, Java I0 流的 40 多個類都是從以下 4 個抽象類基類中派生出來的。

  • InputStream/Reader: 全部的輸入流的基類,前者是字節輸入流,後者是字符輸入流。
  • OutputStream/Writer: 全部輸出流的基類,前者是字節輸出流,後者是字符輸出流。

按操做方式分類結構圖:

相關文章
相關標籤/搜索