1. 程式人生 > >Java面試題——中級(下)

Java面試題——中級(下)

完成 通過 false 有名管道 我們 服務 子元素 服務器 運行時

內部類和靜態內部類的區別

內部類:

1、內部類中的變量和方法不能聲明為靜態的。

2、內部類實例化:B是A的內部類,實例化B:A.B b = new A().new B()。

3、內部類可以引用外部類的靜態或者非靜態屬性及方法。

靜態內部類:

1、靜態內部類屬性和方法可以聲明為靜態的或者非靜態的。

2、實例化靜態內部類:B是A的靜態內部類,A.B b = new A.B()。

3、靜態內部類只能引用外部類的靜態的屬性及方法。

inner classes——內部類

static nested classes——靜態嵌套類

其實人家不叫靜態內部類,只是叫習慣了,從字面就很容易理解了。

內部類依靠外部類的存在為前提,而靜態嵌套類則可以完全獨立,明白了這點就很好理解了。

非靜態內部類中的變量和方法不能聲明為靜態的原因

靜態類型的屬性和方法,在類加載的時候就會存在於內存中。使用某個類的靜態屬性和方法,那麽這個類必須要加載到虛擬機中。但是非靜態內部類並不隨外部類一起加載,只有在實例化外部類之後才會加載。

我們設想一個場景:在外部類並沒有實例化,內部類還沒有加載的時候如果調用內部類的靜態成員或方法,內部類還沒有加載,卻試圖在內存中創建該內部類的靜態成員,就會產生沖突。所以非靜態內部類不能有靜態成員變量或靜態方法。

String,StringBuilder,StringBuffer的區別

String 字符串常量

StringBuffer 字符串變量(線程安全)

StringBuilder 字符串變量(非線程安全)

性能上通常StringBuilder > StringBuffer > String。

String是不可變對象,每次對String類型進行改變的時候都等同於生成了一個新的String對象,然後將指針指向新的String對象,所以性能最差,對於要經常改變內容的字符串不用String。

StringBuffer是字符串變量,對它操作時,並不會生成新的對象,而是直接對該對象進行更改,所以性能較好。

StringBuilder和StringBuffer一樣,是字符串變量,但是他不帶有synchronized關鍵字,不保證線程安全,所以性能最好。在單線程的情況下,建議使用StringBuilder。

總體來說:

String:適用於少量的字符串操作的情況。

StringBuilder:適用於單線程下在字符緩沖區進行大量操作的情況。

StringBuffer:適用多線程下在字符緩沖區進行大量操作的情況。

來一些問題:

下面這段代碼的輸出結果是什麽?

String a = "helloworld";
String b = "hello" + "world";
System.out.println((a == b));

輸出結果為:True。

原因是String對字符串的直接相加,會在編譯期進行優化。即hello+world在編譯時期,被優化為helloworld,所以在運行時期,他們指向了同一個對象。我們也可以推理,對於直接字符串的相加,String不一定比其余兩個慢。

下面這段代碼的輸出結果是什麽?

String a = "helloworld";
String b = "hello";       
String c = b + "world";       
System.out.println((a == c));

輸出結果為:False。

原因是c並非兩個字符串直接相加,包含了一個字符串引用,這時不會做編譯期的優化。所以a、c最終生成了兩個對象,這時他的效率低。

集合和數組之間的相互轉換

數組變集合:

通常我們會回答的是以下代碼:

List<String> list = Arrays.asList(array);

但這並不是很好的答案,此時組合成的list是Arrays裏面的一個靜態內部類,該類並未實現add、remove方法,因此在使用時存在問題。

可以這樣:

String array[]= {"hello","world","java","zhiyin"};
List<String> list = new ArrayList<String>(Arrays.asList(array));

集合變數組:

String[] array=list.toArray(new String[list.size()]);

面向對象的特征有哪些方面?

  • 抽象:抽象是將一類對象的共同特征總結出來構造類的過程,包括數據抽象和行為抽象兩方面。抽象只關註對象有哪些屬性和行為,並不關註這些行為的細節是什麽。

  • 繼承:繼承是從已有類得到繼承信息創建新類的過程。提供繼承信息的類被稱為父類;得到繼承信息的類被稱為子類。繼承讓變化中的軟件系統有了一定的延續性,同時繼承也是封裝程序中可變因素的重要手段。

  • 封裝:通常認為封裝是把數據和操作數據的方法綁定起來,對數據的訪問只能通過已定義的接口。面向對象的本質就是將現實世界描繪成一系列完全自治、封閉的對象。我們在類中編寫的方法就是對實現細節的一種封裝;我們編寫一個類就是對數據和數據操作的封裝。可以說,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口。

  • 多態性:多態性是指允許不同子類型的對象對同一消息作出不同的響應。簡單的說就是用同樣的對象引用調用同樣的方法但是做了不同的事情。多態性分為編譯時的多態性和運行時的多態性。方法重載實現的是編譯時的多態性,而方法重寫實現的是運行時的多態性。

概括的解釋下線程的幾種狀態

  1. 就緒(Runnable):線程準備運行,不一定立馬就能開始執行。

  2. 運行中(Running):進程正在執行線程的代碼。

  3. 等待中(Waiting):線程處於阻塞的狀態,等待外部的處理結束。

  4. 睡眠中(Sleeping):線程被強制睡眠。

  5. I/O阻塞(Blocked on I/O):等待I/O操作完成。

  6. 同步阻塞(Blocked on Synchronization):等待獲取鎖。

  7. 死亡(Dead):線程完成了執行。

Java集合類裏面基本的接口有哪些

  • Collection:代表一組對象,每一個對象都是它的子元素。

  • Set:不包含重復元素的Collection。

  • List:有順序的collection,並且可以包含重復元素。

  • Map:可以把鍵(key)映射到值(value)的對象,鍵不能重復。

Iterator和ListIterator的區別

  • Iterator可用來遍歷Set和List集合,但是ListIterator只能用來遍歷List。

  • Iterator對集合只能是前向遍歷,ListIterator既可以前向遍歷也可以後向遍歷。

  • ListIterator實現了Iterator接口,並包含其他的功能,比如:增加、替換元素,獲取前一個和後一個元素的索引等等。

Enumeration和Iterator的區別

  • java中的集合類都提供了返回Iterator的方法,就是叠代器,它和Enumeration(枚舉)的主要區別其實就是Iterator可以刪除元素,但是Enumration卻不能。

  • 使用Iterator來遍歷集合時,應使用Iterator的remove()方法來刪除集合中的元素,使用集合的remove()方法將拋出ConcurrentModificationException異常。

  • Enumeration接口的功能和Iterator接口的功能是重復的。此外,Iterator 接口添加了一個可選的移除操作,並使用較短的方法名。新的實現應該優先考慮使用Iterator接口而不是Enumeration接口。

  • Enumeration速度是Iterator的2倍,同時占用更少的內存。但是,Iterator遠遠比Enumeration安全,因為其他線程不能夠修改正在被iterator遍歷的集合裏面的對象。

介紹一下HTTP的響應結構

請求報文的組成:

  • 請求方法。

  • 請求的資源的URI。

  • 協議版本。

  • 可選的請求首部字段。

  • 內容實體。

響應報文的組成:

  • 協議版本。

  • 狀態碼。

  • 用於解釋狀態碼的原因短語。

  • 可選的響應首部字段。

  • 實體主體。

響應:

  • 響應碼:回應客戶端此次響應是否成功。如:404(找不到請求的資源),500(服務器內部錯誤),200(成功響應)等。

  • 消息頭:服務器與客戶端通信的暗碼,告訴客戶端該怎麽執行某些操作。

  • 響應正文:傳遞服務器響應給客戶端要顯示的內容,可以是下載文件或者顯示界面。

final、finalize和finally各自的作用

final是一個修飾符,可以修飾變量、方法和類。如果 final 修飾變量,意味著該變量的值在初始化後不能被改變。

finalize方法是在對象被回收之前調用的方法,給對象自己最後一個復活的機會,但是什麽時候調用 finalize 沒有保證。

finally是一個關鍵字,與try和catch一起用於異常的處理。finally塊一定會被執行,無論在try塊中是否有發生異常。

說一下你了解的幾種進程間的通信方式

  • 管道pipe:管道是一種半雙工的通信方式,數據只能單向流動,而且只能在具有親緣關系的進程間使用。進程的親緣關系通常是指父子進程關系。

  • 高級管道popen:將另一個程序當做一個新的進程在當前程序進程中啟動,則它算是當前程序的子進程,這種方式我們成為高級管道方式。

  • 有名管道named pipe :有名管道也是半雙工的通信方式,但是它允許無親緣關系進程間的通信。

  • 消息隊列MessageQueue:消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩沖區大小受限等缺點。

  • 共享存儲SharedMemory:共享內存就是映射一段能被其他進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問。共享內存是最快的 IPC 方式,它是針對其他進程間通信方式運行效率低而專門設計的。它往往與其他通信機制,如信號兩,配合使用,來實現進程間的同步和通信。

  • 信號量Semaphore:信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作為一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作為進程間以及同一進程內不同線程之間的同步手段。

  • 套接字Socket:套解口也是一種進程間通信機制,與其他通信機制不同的是,它可用於不同及其間的進程通信。

  • 信號sinal: 信號是一種比較復雜的通信方式,用於通知接收進程某個事件已經發生。

Java面試題——中級(下)