Java面試題-Java特性
1, 一個類實現了一個介面,需要過載這個介面的所有方法,還是重寫這個介面的所有方法?
答案:Override,重寫。
引申:
過載(Overload),是指一個類中有多個同名方法,但這些方法有著不同引數,因此可以在編譯時決定到底用哪個方法,是一種編譯時多型。
重寫(Override),子類重寫父類方法,導致同樣的方法在子類和父類中有著不同的表現形式,而程式呼叫方法是在執行期動態繫結,是一種執行時多型。
2, 對於一些敏感資料是儲存為字元陣列還是字串更安全?
答案:字元陣列
引申:
在Java語言中,String是不可變類,它被儲存在字串常量池中,從而實現了字串的共享,減少了記憶體的開支。但當這個資料不再使用,它仍會在常量池中存在一段時間,只有垃圾回收器能夠回收。因此有許可權訪問memory dump(儲存器轉儲,將記憶體中的資料寫入到檔案)的程式都能訪問到這個資料。而字元陣列當不用的時候,程式設計師可以把其內容置空,從而有效的控制了資料的生命週期。
3, volatile關鍵字有什麼作用?
答案:該欄位用於修飾被多執行緒訪問的屬性,以保證對屬性的修改對所有執行緒可見,每次取到的都是最新的值。
引申:
相比於synchronized,它僅用於修飾欄位,且它只保持執行緒安全三要素中可見性和有序性,並不能保證操作的原子性,所以不能保證嚴格保證執行緒安全。
Volatile的實現基於記憶體柵欄(Memory Barrier),一個volatile欄位修改時,JVM會執行一個Write-Barrier
操作,該操作將當前處理器快取的資料寫會系統記憶體,並使其他CPU核心裡引用了該地址的資料變為髒資料。當讀取時,JVM會多執行一個Read-Barrier指令,如果該資料已經變髒,如果該資料已經變髒,那麼從主存中重新獲取資料。
4,Java反射是什麼?獲取Class物件有哪些方法,他們的區別是什麼?
答案:Java中反射是指動態獲取類或物件的屬性與方法從而完成呼叫功能的手段。
獲取Class物件有三種方式及其特點(區別)為:
l className.class(不執行靜態塊和動態構造塊)
l Class.forName()(執行靜態塊,不執行動態構造塊)
l Object.getClass()(因為需要建立物件,會執行靜態塊和動態構造塊)
引申:
例項化一個類時,對於類中程式碼的執行順序(假定A為父類,B繼承A,B中main方法例項化B):
1 public class A {
2 public A() {
3 System.out.println("A 類構造方法執行");
4 }
5 {System.out.println("A 類動態程式碼塊執行");}
6 static {System.out.println("A 類靜態程式碼塊執行");}
7 }
1 public class B extends A{
2 public B() {
3 System.out.println("B 類構造方法執行");
4 }
5 {System.out.println("B 類動態程式碼塊執行");}
6 static {System.out.println("B 類靜態程式碼塊執行");}
7 public static void main(String[] args) {
8 System.out.println("start");
9 new B();
10 System.out.println("end");
11 }
12 /*
13 * A 類靜態程式碼塊執行
14 * B 類靜態程式碼塊執行
15 * start
16 * A 類動態程式碼塊執行
17 * A 類構造方法執行
18 * B 類動態程式碼塊執行
19 * B 類構造方法執行
20 * end
21 */
22 }
5, 巢狀類(內部類)都有哪些?
答案:內部類主要有四種:靜態內部類、成員內部類、區域性(方法)內部類、匿名內部類
引申:
靜態內部類(static inner class)可以不依賴外部例項而被例項化,不能訪問外部類普通成員變數,只能訪問外部類中靜態成員和靜態方法(包括私有型別)。
成員內部類(member inner class)只有當外部類被例項化後才能被例項化,可以自由引用外部類的屬性和方法。
區域性(方法)內部類(local inner class)指定義在一個程式碼塊內的類,作用範圍只在程式碼塊內,訪問許可權和成員內部類相似。
匿名內部類(anonymous inner class)沒有類名,不使用關鍵字class,內部不能有建構函式,不能定義靜態變數、方法和類。必須繼承其它類或實現某個介面,訪問許可權和成員內部類相似。
6,泛型的本質是什麼?java中的泛型是真泛型還是偽泛型?為什麼這樣設計?
答案:泛型的本質是一個引數化型別,為了實現在執行時確定引數的型別而提出。是偽泛型,為了對老程式的向下相容。
引申:
泛型擦除:Java的泛型不存在於執行時,而是在編譯器處理帶泛型的類、介面或方法時會在位元組碼指令中抹去全部泛型型別資訊。因此有好多注意的點,比如泛型不能用於方法過載、泛型不能用於自定義異常類,instanceOf後邊的類泛型只能用?
1 list instanceOf ArrayList<?> 正確
2 list instanceOf ArrayList<String> 錯誤
編譯器將java原始碼編譯為位元組碼(面向JVM的原始碼)後,擦除了泛型,但是會在位元組碼註釋中保留一些泛型資訊,這些資訊稱為方法簽名,java之所以這樣設計,是為了相容性的考慮,低版本的位元組碼和高版本基本上只有簽名上不一樣,不影響功能體,因此低版本的位元組碼可以不做任何改動就在高版本的虛擬機器裡執行。因為對List,具體的型別引數資訊在編譯時都會被擦除,那麼<>中的東西顯然是不能確定的。
7,java介面可以有方法體嗎?這樣做的好處是什麼?
答案:從jdk1.8開始可以使用default和static關鍵字最介面中方法新增預設實現和靜態實現。好處是降低對介面升級的代價,升級功能只改一下介面的實現即可全部升級。
引申:
從JDK1.9開始,介面不僅能夠寫帶有方法體的方法,還能定義私有方法,目的是為了加強程式碼重用性,減少冗餘,同時實現程式碼隱藏。
8,java函式式介面都有哪些?
答案:Function、Consumer、Supplier、Predicate
9,簡單介紹一下Java訪問許可權?
答案:java許可權大致分為四類:
|
private |
預設訪問許可權 |
protected |
public |
類本身 |
是 |
是 |
是 |
是 |
相同包中子類 |
否 |
是 |
是 |
是 |
相同包中的非子類 |
否 |
是 |
是 |
是 |
不同包中的子類 |
否 |
否 |
是 |
是 |
不同包中的非子類子類 |
否 |
否 |
否 |
是 |
但是從JDK1.9開始引入模組化概念,模組系統的出現意味著public不是對所有類可見了,如果一個類被修飾為public,那麼它只能是在模組內是public的,不能被其它模組訪問,除非這個模組被其它模組使用require來引用。這顯然增加了程式的封裝性。
10,try-with-resources語法JDK7與JDK9有什麼區別?
答案:在JDK7中try語句塊中不能使用外部宣告的任何資源,使用時需要增加一個額外的引用
1 try(InputStream fis1=fis)
JDK9針對這個缺陷進行了改進,try塊中可以直接引用外部宣告的資源,程式碼變得更加簡潔。
1 try(fis)
11,lambda表示式中takeWhile、dropWhile和Filter的區別與聯絡?
答案:這三個方法都使用了一個斷言(四大核心函式式介面之一的Predicate)作為引數,不同的是takeWhile會返回從頭元素開始直到斷言語句為false為止的stream子集。DropWhile恰恰相反,直到斷言第一次返回true才開始返回直到尾部stream子集。Filter則是返回斷言為true的所有元素。