2019年Java面試題基礎系列228道(1),快看看哪些你還不會?

Java面試題(一)

1、面向對象的特徵有哪些方面?

2、訪問修飾符 public,private,protected,以及不寫(默認)時的區別?

3、String 是最基本的數據類型嗎?

4、float f=3.4;是否正確?

5、short s1 = 1; s1 = s1 + 1;有錯嗎?short s1 = 1; s1 += 1;有錯嗎?

6、Java 有沒有 goto?

7、int 和 Integer 有什麼區別?

8、&和&&的區別?

9、解釋內存中的棧(stack)、堆(heap)和方法區(method area)的用法。

10、Math.round(11.5) 等於多少?Math.round(-11.5)等於多少?

11、switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上?

12、用最有效率的方法計算 2 乘以 8?

13、數組有沒有 length()方法?String 有沒有 length()方法?

14、在 Java 中,如何跳出當前的多重嵌套循環?

15、構造器(constructor)是否可被重寫(override)?

16、兩個對象值相同(x.equals(y) == true),但卻可有不同的 hashcode,這句話對不對?

17、是否可以繼承 String 類?

18、當一個對象被當作參數傳遞到一個方法後,此方法可改變這個對象的屬性,並可返回變化後的結果,那麼這裏到底是值傳遞還是引用傳遞?

19、String 和 StringBuilder、StringBuffer 的區別?

20、重載(Overload)和重寫(Override)的區別。重載的方法能否根據返回類型進行區分?

21、描述一下 JVM 加載 class 文件的原理機制?

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

23、抽象類(abstract class)和接口(interface)有什麼異同?

24、靜態嵌套類(Static Nested Class)和內部類(Inner Class)的不同?

25、Java 中會存在內存泄漏嗎,請簡單描述。

26、抽象的(abstract)方法是否可同時是靜態的(static),是否可同時是本地方法(native),是否可同時被 synchronized 修飾?

27、闡述靜態變量和實例變量的區別。

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

29、如何實現對象克隆?

30、GC 是什麼?爲什麼要有 GC?

31、String s = new String(“xyz”);創建了幾個字符串對象?

32 、 接 口 是 否 可 繼 承 ( extends ) 接 口 ? 抽 象 類 是 否 可 實 現(implements)接口?抽象類是否可繼承具體類(concrete class)?

33、一個”.java”源文件中是否可以包含多個類(不是內部類)?有什麼限制?

34、Anonymous Inner Class(匿名內部類)是否可以繼承其它類?是否可以實現接口?

35、內部類可以引用它的包含類(外部類)的成員嗎?有沒有什麼限制?

36、Java 中的 final 關鍵字有哪些用法?

37、指出下面程序的運行結果

38、數據類型之間的轉換:

39、如何實現字符串的反轉及替換?

40、怎樣將 GB2312 編碼的字符串轉換爲 ISO-8859-1 編碼的字符串?

41、日期和時間:

42、打印昨天的當前時刻。

43、比較一下 Java 和 JavaSciprt。

44、什麼時候用斷言(assert)?

45、Error 和 Exception 有什麼區別?

46、try{}裏有一個 return 語句,那麼緊跟在這個 try 後的 finally{}裏的代碼會不會被執行,什麼時候被執行,在 return 前還是後?

47、Java 語言如何進行異常處理,關鍵字:throws、throw、try、catch、finally 分別如何使用?

48、運行時異常與受檢異常有何異同?

49、列出一些你常見的運行時異常?

50、闡述 final、finally、finalize 的區別。

51、類 ExampleA 繼承 Exception,類 ExampleB 繼承 ExampleA。

52、List、Set、Map 是否繼承自 Collection 接口?

53、闡述 ArrayList、Vector、LinkedList 的存儲性能和特性。

54、Collection 和 Collections 的區別?

55、List、Map、Set 三個接口存取元素時,各有什麼特點?

56、TreeMap 和 TreeSet 在排序時如何比較元素?Collections 工具類中的 sort()方法如何比較元素?

57、Thread 類的 sleep()方法和對象的 wait()方法都可以讓線程暫停執行,它們有什麼區別?

58、線程的 sleep()方法和 yield()方法有什麼區別?

59、當一個線程進入一個對象的 synchronized 方法 A 之後,其它線程是否可進入此對象 synchronized 方法 B?

60、請說出與線程同步以及線程調度相關的方法。

61、編寫多線程程序有幾種實現方式?

62、synchronized 關鍵字的用法?

63、舉例說明同步和異步。

64、啓動一個線程是調用 run()還是 start()方法?

65、什麼是線程池(thread pool)?

66、線程的基本狀態以及狀態之間的關係?

67、簡述 synchronized 和 java.util.concurrent.locks.Lock 的異同?

68、Java 中如何實現序列化,有什麼意義?

69、Java 中有幾種類型的流?

70、寫一個方法,輸入一個文件名和一個字符串,統計這個字符串在這個文件中出現的次數。

71、如何用 Java 代碼列出一個目錄下所有的文件?

72、用 Java 的套接字編程實現一個多線程的回顯(echo)服務器。

73、XML 文檔定義有幾種形式?它們之間有何本質區別?解析 XML文檔有哪幾種方式?

74、你在項目中哪些地方用到了 XML?

75、闡述 JDBC 操作數據庫的步驟。

76、Statement 和 PreparedStatement 有什麼區別?哪個性能更好?

77、使用 JDBC 操作數據庫時,如何提升讀取數據的性能?如何提升更新數據的性能?

78、在進行數據庫編程時,連接池有什麼作用?

79、什麼是 DAO 模式?

80、事務的 ACID 是指什麼?

82、JDBC 能否處理 Blob 和 Clob?

83、簡述正則表達式及其用途。

84、Java 中是如何支持正則表達式操作的?

85、獲得一個類的類對象有哪些方式?

88、如何通過反射調用對象的方法?

90、簡述一下你瞭解的設計模式。

91、用 Java 寫一個單例類。

92、什麼是 UML?

93、UML 中有哪些常用的圖?

95、用 Java 寫一個折半查找。

Java 面試題(二)

1、Java 中能創建 volatile 數組嗎?

2、volatile 能使得一個非原子操作變成原子操作嗎?

3、volatile 修飾符的有過什麼實踐?

4、volatile 類型變量提供什麼保證?

5、10 個線程和 2 個線程的同步代碼,哪個更容易寫?

6、你是如何調用 wait()方法的?使用 if 塊還是循環?爲什麼?

8、什麼是 Busy spin?我們爲什麼要使用它?

9、Java 中怎麼獲取一份線程 dump 文件?

10、Swing 是線程安全的?

11、什麼是線程局部變量?

12、用 wait-notify 寫一段代碼來解決生產者-消費者問題?

13、用 Java 寫一個線程安全的單例模式(Singleton)?

14、Java 中 sleep 方法和 wait 方法的區別?

15、什麼是不可變對象(immutable object)?Java 中怎麼創建一個不可變對象?

16、我們能創建一個包含可變對象的不可變對象嗎?

17、Java 中應該使用什麼數據類型來代表價格?

18、怎麼將 byte 轉換爲 String?

19、Java 中怎樣將 bytes 轉換爲 long 類型?

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

21、存在兩個類,B 繼承 A ,C 繼承 B,我們能將 B 轉換爲 C 麼?如 C = (C) B;

22、哪個類包含 clone 方法?是 Cloneable 還是 Object?

23、Java 中 ++ 操作符是線程安全的嗎?

23、不是線程安全的操作。它涉及到多個指令,如讀取變量值,增加,然後存儲回內存,這個過程可能會出現多個線程交差。

24、a = a + b 與 a += b 的區別

25、我能在不進行強制轉換的情況下將一個 double 值賦值給 long類型的變量嗎?

26、3*0.1 == 0.3 將會返回什麼?true 還是 false?

27、int 和 Integer 哪個會佔用更多的內存?

28、爲什麼 Java 中的 String 是不可變的(Immutable)?

31、64 位 JVM 中,int 的長度是多數?

32、Serial 與 Parallel GC 之間的不同之處?

33、32 位和 64 位的 JVM,int 類型變量的長度是多數?

34、Java 中 WeakReference 與 SoftReference 的區別?

35、WeakHashMap 是怎麼工作的?

36、JVM 選項 -XX:+UseCompressedOops 有什麼作用?爲什麼要使用?

37、怎樣通過 Java 程序來判斷 JVM 是 32 位 還是 64 位?

38、32 位 JVM 和 64 位 JVM 的最大堆內存分別是多數?

39、JRE、JDK、JVM 及 JIT 之間有什麼不同?

40、解釋 Java 堆空間及 GC?

41、你能保證 GC 執行嗎?

42、怎麼獲取 Java 程序使用的內存?堆使用的百分比?

43、Java 中堆和棧有什麼區別?

44、“a==b”和”a.equals(b)”有什麼區別?

45、a.hashCode() 有什麼用?與 a.equals(b) 有什麼關係?

46、final、finalize 和 finally 的不同之處?

47、Java 中的編譯期常量是什麼?使用它又什麼風險?

48、List、Set、Map 和 Queue 之間的區別(答案)

49、poll() 方法和 remove() 方法的區別?

50、Java 中 LinkedHashMap 和 PriorityQueue 的區別是什麼?

51、ArrayList 與 LinkedList 的不區別?

52、用哪兩種方式來實現集合的排序?

53、Java 中怎麼打印數組?

54、Java 中的 LinkedList 是單向鏈表還是雙向鏈表?

55、Java 中的 TreeMap 是採用什麼樹實現的?(答案)

56、Hashtable 與 HashMap 有什麼不同之處?

57、Java 中的 HashSet,內部是如何工作的?

58、寫一段代碼在遍歷 ArrayList 時移除一個元素?

59、我們能自己寫一個容器類,然後使用 for-each 循環碼?

60、ArrayList 和 HashMap 的默認大小是多數?

61、有沒有可能兩個不相等的對象有有相同的 hashcode?

62、兩個相同的對象會有不同的的 hash code 嗎?

63、我們可以在 hashcode() 中使用隨機數字嗎?

64、Java 中,Comparator 與 Comparable 有什麼不同?

66、在我 Java 程序中,我有三個 socket,我需要多少個線程來處理?

67、Java 中怎麼創建 ByteBuffer?

68、Java 中,怎麼讀寫 ByteBuffer ?

69、Java 採用的是大端還是小端?

70、ByteBuffer 中的字節序是什麼?

71、Java 中,直接緩衝區與非直接緩衝器有什麼區別?

72、Java 中的內存映射緩存區是什麼?

73、socket 選項 TCP NO DELAY 是指什麼?

74、TCP 協議與 UDP 協議有什麼區別?

75、Java 中,ByteBuffer 與 StringBuffer 有什麼區別?(答案)

76、Java 中,編寫多線程程序的時候你會遵循哪些最佳實踐?

77、說出幾點 Java 中使用 Collections 的最佳實踐

78、說出至少 5 點在 Java 中使用線程的最佳實踐。

79、說出 5 條 IO 的最佳實踐(答案)

80、列出 5 個應該遵循的 JDBC 最佳實踐

81、說出幾條 Java 中方法重載的最佳實踐?

82、在多線程環境下,SimpleDateFormat 是線程安全的嗎?

83、Java 中如何格式化一個日期?如格式化爲 ddMMyyyy 的形式?

84、Java 中,怎麼在格式化的日期中顯示時區?

85、Java 中 java.util.Date 與 java.sql.Date 有什麼區別?

86、Java 中,如何計算兩個日期之間的差距?

87、Java 中,如何將字符串 YYYYMMDD 轉換爲日期?

89、如何測試靜態方法?(答案)

90、怎麼利用 JUnit 來測試一個方法的異常?

91、你使用過哪個單元測試庫來測試你的 Java 程序?

92、@Before 和 @BeforeClass 有什麼區別?

93、怎麼檢查一個字符串只包含數字?解決方案

94、Java 中如何利用泛型寫一個 LRU 緩存?

95、寫一段 Java 程序將 byte 轉換爲 long?

96、在不使用 StringBuffer 的前提下,怎麼反轉一個字符串?

97、Java 中,怎麼獲取一個文件中單詞出現的最高頻率?

98、如何檢查出兩個給定的字符串是反序的?

99、Java 中,怎麼打印出一個字符串的所有排列?

100、Java 中,怎樣才能打印出數組中的重複元素?

101、Java 中如何將字符串轉換爲整數?

102、在沒有使用臨時變量的情況如何交換兩個整數變量的值?

103、接口是什麼?爲什麼要使用接口而不是直接使用具體類?

104、Java 中,抽象類與接口之間有什麼不同?

105、除了單例模式,你在生產環境中還用過什麼設計模式?

106、你能解釋一下里氏替換原則嗎?

107、什麼情況下會違反迪米特法則?爲什麼會有這個問題?

108、適配器模式是什麼?什麼時候使用?

109、什麼是“依賴注入”和“控制反轉”?爲什麼有人使用?

110、抽象類是什麼?它與接口有什麼區別?你爲什麼要使用過抽象類?

111、構造器注入和 setter 依賴注入,那種方式更好?

112、依賴注入和工程模式之間有什麼不同?

113、適配器模式和裝飾器模式有什麼區別?

114、適配器模式和代理模式之前有什麼不同?

115、什麼是模板方法模式?

116、什麼時候使用訪問者模式?

117、什麼時候使用組合模式?

118、繼承和組合之間有什麼不同?

119、描述 Java 中的重載和重寫?

120、Java 中,嵌套公共靜態類與頂級類有什麼不同?

121、 OOP 中的 組合、聚合和關聯有什麼區別?

122、給我一個符合開閉原則的設計模式的例子?

123、抽象工廠模式和原型模式之間的區別?

125、嵌套靜態類與頂級類有什麼區別?

126、你能寫出一個正則表達式來判斷一個字符串是否是一個數字嗎?

127、Java 中,受檢查異常 和 不受檢查異常的區別?

128、Java 中,throw 和 throws 有什麼區別

129、Java 中,Serializable 與 Externalizable 的區別?

130、Java 中,DOM 和 SAX 解析器有什麼不同?

131、說出 JDK 1.7 中的三個新特性?

132、說出 5 個 JDK 1.8 引入的新特性?

133、Java 中,Maven 和 ANT 有什麼區別?

v2-c1ac05f8cfc8513798eb58981a75adc3_hd.png


本次更新Java 面試題(一)的1~20題答案

1、面向對象的特徵有哪些方面?

面向對象的特徵主要有以下幾個方面:

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

繼承:繼承是從已有類得到繼承信息創建新類的過程。提供繼承信息的類被稱爲父類(超類、基類);得到繼承信息的類被稱爲子類(派生類)。繼承讓變化中的軟件系統有了一定的延續性,同時繼承也是封裝程序中可變因素的重要手段(如果不能理解請閱讀閻宏博士的《Java 與模式》或《設計模式精解》中關於橋樑模式的部分)。

封裝:通常認爲封裝是把數據和操作數據的方法綁定起來,對數據的訪問只能通過已定義的接口。面向對象的本質就是將現實世界描繪成一系列完全自治、封閉的對象。我們在類中編寫的方法就是對實現細節的一種封裝;我們編寫一個類就是對數據和數據操作的封裝。可以說,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口(可以想想普通洗衣機和全自動洗衣機的差別,明顯全自動洗衣機封裝更好因此操作起來更簡單;我們現在使用的智能手機也是封裝得足夠好的,因爲幾個按鍵就搞定了所有的事情)。

多態性:多態性是指允許不同子類型的對象對同一消息作出不同的響應。簡單的說就是用同樣的對象引用調用同樣的方法但是做了不同的事情。多態性分爲編譯時的多態性和運行時的多態性。如果將對象的方法視爲對象向外界提供的服務,那麼運行時的多態性可以解釋爲:當 A 系統訪問 B 系統提供的服務時,B系統有多種提供服務的方式,但一切對 A 系統來說都是透明的(就像電動剃鬚刀是 A 系統,它的供電系統是 B 系統,B 系統可以使用電池供電或者用交流電,甚至還有可能是太陽能,A 系統只會通過 B 類對象調用供電的方法,但並不知道供電系統的底層實現是什麼,究竟通過何種方式獲得了動力)。方法重載(overload)實現的是編譯時的多態性(也稱爲前綁定),而方法重寫(override)實現的是運行時的多態性(也稱爲後綁定)。運行時的多態是面向對象最精髓的東西,要實現多態需要做兩件事:

1). 方法重寫(子類繼承父類並重寫父類中已有的或抽象的方法); 2). 對象造型(用父類型引用引用子類型對象,這樣同樣的引用調用同樣的方法就會根據子類對象的不同而表現出不同的行爲)。

2、訪問修飾符 public,private,protected,以及不寫(默認)時的區別?

修飾符 當前類 同 包 子 類 其他包

v2-dbff82296d49870a194c7d206dfdd171_hd.jpg

類的成員不寫訪問修飾時默認爲 default。默認對於同一個包中的其他類相當於公開(public),對於不是同一個包中的其他類相當於私有(private)。受保護(protected)對子類相當於公開,對不是同一包中的沒有父子關係的類相當於私有。Java 中,外部類的修飾符只能是 public 或默認,類的成員(包括內部類)的修飾符可以是以上四種。

3、String 是最基本的數據類型嗎?

不是。Java 中的基本數據類型只有 8 個 :byte、short、int、long、float、double、char、boolean;除了基本類型(primitive type),剩下的都是引用類型(referencetype),Java 5 以後引入的枚舉類型也算是一種比較特殊的引用類型。

4、float f=3.4;是否正確?

不正確。3.4 是雙精度數,將雙精度型(double)賦值給浮點型(float)屬於下轉型(down-casting,也稱爲窄化)會造成精度損失,因此需要強制類型轉換float f =(float)3.4; 或者寫成 float f =3.4F;。

5、short s1 = 1; s1 = s1 + 1;有錯嗎?short s1 = 1; s1 += 1;有錯嗎?

對於 short s1 = 1; s1 = s1 + 1;由於 1 是 int 類型,因此 s1+1 運算結果也是 int型,需要強制轉換類型才能賦值給 short 型。而 short s1 = 1; s1 += 1;可以正確編譯,因爲 s1+= 1;相當於 s1 = (short(s1 + 1);其中有隱含的強制類型轉換。

6、Java 有沒有 goto?

goto 是 Java 中的保留字,在目前版本的 Java 中沒有使用。(根據 James Gosling(Java 之父)編寫的《The Java Programming Language》一書的附錄中給出了一個 Java 關鍵字列表,其中有goto 和 const,但是這兩個是目前無法使用的關鍵字,因此有些地方將其稱之爲保留字,其實保留字這個詞應該有更廣泛的意義,因爲熟悉 C 語言的程序員都知道,在系統類庫中使用過的有特殊意義的但詞或單詞的組合都被視爲保留字)

7、int 和 Integer 有什麼區別?

Java 是一個近乎純潔的面向對象編程語言,但是爲了編程的方便還是引入了基本數據類型,但是爲了能夠將這些基本數據類型當成對象操作,Java 爲每一個基本數據類型都引入了對應的包裝類型(wrapper class),int 的包裝類就是 Integer,從 Java 5 開始引入了自動裝箱/拆箱機制,使得二者可以相互轉換。

Java 爲每個原始類型提供了包裝類型:

原始類型: boolean,char,byte,short,int,long,float,double

包裝類型:Boolean,Character,Byte,Short,Integer,Long,Float,Double

class AutoUnboxingTest {
	public static void main(String[] args) {
		Integer a = new Integer(3);
		Integer b = 3;
		// 將 3 自動裝箱成 Integer 類型
		int c = 3;
		System.out.println(a == b);
		// false 兩個引用沒有引用同一對
		象
		System.out.println(a == c);
		// true a 自動拆箱成 int 類型再和 c
		比較
	}
}

最近還遇到一個面試題,也是和自動裝箱和拆箱有點關係的,代碼如下所示:

public class Test03 {
	public static void main(String[] args) {
		Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
		System.out.println(f1 == f2);
		System.out.println(f3 == f4);
	}
}

如果不明就裏很容易認爲兩個輸出要麼都是 true 要麼都是 false。首先需要注意的是 f1、f2、f3、f4 四個變量都是 Integer 對象引用,所以下面的==運算比較的不是值而是引用。裝箱的本質是什麼呢?當我們給一個 Integer 對象賦一個 int 值的時候,會調用 Integer 類的靜態方法 valueOf,如果看 valueOf 的源代碼就知道發生了什麼。

public static Integer valueOf(int i) {
	if (i >= IntegerCache.low && i <= IntegerCache.high)
	return IntegerCache.cache[i + (-IntegerCache.low)];
	return new Integer(i);
}

IntegerCache 是 Integer 的內部類,其代碼如下所示:

/**
* Cache to support the object identity semantics of autoboxing for
values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>}
option.
* During VM initialization, java.lang.Integer.IntegerCache.high
property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
private static class IntegerCache {
	static final int low = -128;
	static final int high;
	static final Integer cache[];
	static {
		// high value may be configured by property
		int h = 127;
		String integerCacheHighPropValue =
		sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
		if (integerCacheHighPropValue != null) {
			try {
				int i = parseint(integerCacheHighPropValue);
				i = Math.max(i, 127);
				// Maximum array size is Integer.MAX_VALUE
				h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
			}
			catch( NumberFormatException nfe) {
				// If the property cannot be parsed into an int,
				ignore it.
			}
		}
		high = h;
		cache = new Integer[(high - low) + 1];
		int j = low;
		for (int k = 0; k < cache.length; k++)
		cache[k] = new Integer(j++);
		// range [-128, 127] must be interned (JLS7 5.1.7)
		assert IntegerCache.high >= 127;
	}
	private IntegerCache() {
	}
}

簡單的說,如果整型字面量的值在-128 到 127 之間,那麼不會 new 新的 Integer對象,而是直接引用常量池中的 Integer 對象,所以上面的面試題中 f1f4 的結果是 false。

提醒:越是貌似簡單的面試題其中的玄機就越多,需要面試者有相當深厚的功力。

v2-a41576aa0226ac4da6e7023088af1aab_hd.png

8、&和&&的區別?

&運算符有兩種用法:(1)按位與;(2)邏輯與。&&運算符是短路與運算。邏輯與跟短路與的差別是非常巨大的,雖然二者都要求運算符左右兩端的布爾值都是true 整個表達式的值纔是 true。&&之所以稱爲短路運算是因爲,如果&&左邊的表達式的值是 false,右邊的表達式會被直接短路掉,不會進行運算。很多時候我們可能都需要用&&而不是&,例如在驗證用戶登錄時判定用戶名不是 null 而且不是空字符串,應當寫爲:username != null &&!username.equals(“”),二者的順序不能交換,更不能用&運算符,因爲第一個條件如果不成立,根本不能進行字符串的 equals 比較,否則會生 NullPointerException 異常。注意:邏輯或運算符(|)和短路或運算符(||)的差別也是如此。

9、解釋內存中的棧(stack)、堆(heap)和方法區(method area)的用法。

通常我們定義一個基本數據類型的變量,一個對象的引用,還有就是函數調用的現場保存都使用 JVM 中的棧空間;而通過 new 關鍵字和構造器創建的對象則放在堆空間,堆是垃圾收集器管理的主要區域,由於現在的垃圾收集器都採用分代收集算法,所以堆空間還可以細分爲新生代和老生代,再具體一點可以分爲 Eden、Survivor(又可分爲 From Survivor 和 To Survivor)、Tenured;方法區和堆都是各個線程共享的內存區域,用於存儲已經被 JVM 加載的類信息、常量、靜態變量、JIT 編譯器編譯後的代碼等數據;程序中的字面量(literal)如直接書寫的 100、”hello”和常量都是放在常量池中,常量池是方法區的一部分,。棧空間操作起來最快但是棧很小,通常大量的對象都是放在堆空間,棧和堆的大小都可以通過 JVM的啓動參數來進行調整,棧空間用光了會引發 StackOverflowError,而堆和常量池空間不足則會引發 OutOfMemoryError。

String str = new String("hello");

上面的語句中變量 str 放在棧上,用 new 創建出來的字符串對象放在堆上,而”hello”這個字面量是放在方法區的。

補充 1:較新版本的 Java(從 Java 6 的某個更新開始)中,由於 JIT 編譯器的發展和”逃逸分析”技術的逐漸成熟,棧上分配、標量替換等優化技術使得對象一定分配在堆上這件事情已經變得不那麼絕對了。

補充 2:運行時常量池相當於 Class 文件常量池具有動態性,Java 語言並不要求常量一定只有編譯期間才能產生,運行期間也可以將新的常量放入池中,String類的 intern()方法就是這樣的。

看看下面代碼的執行結果是什麼並且比較一下 Java 7 以前和以後的運行結果是否一致。

String s1 = new StringBuilder("go")
.append("od").toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder("ja")
.append("va").toString();
System.out.println(s2.intern() == s2);

10、Math.round(11.5) 等於多少?Math.round(-11.5)等於多少?

Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四捨五入的原理是在參數上加 0.5 然後進行下取整。

11、switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上?

在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。從 Java5 開始,Java 中引入了枚舉類型,expr 也可以是 enum 類型,從 Java 7 開始,expr 還可以是字符串(String),但是長整型(long)在目前所有的版本中都是不可以的。

12、用最有效率的方法計算 2 乘以 8?

2 << 3(左移 3 位相當於乘以 2 的 3 次方,右移 3 位相當於除以 2 的 3 次方)。

補充:我們爲編寫的類重寫 hashCode 方法時,可能會看到如下所示的代碼,其實我們不太理解爲什麼要使用這樣的乘法運算來產生哈希碼(散列碼),而且爲什麼這個數是個素數,爲什麼通常選擇 31 這個數?前兩個問題的答案你可以自己百度一下,選擇 31 是因爲可以用移位和減法運算來代替乘法,從而得到更好的性能。說到這裏你可能已經想到了:31 * num 等價於(num << 5) - num,左移 5位相當於乘以 2 的 5 次方再減去自身就相當於乘以 31,現在的 VM 都能自動完成這個優化。

public class PhoneNumber {
	private int areaCode;
	private String prefix;
	private String lineNumber;
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + areaCode;
		result = prime * result
		+ ((lineNumber == null) ? 0 : lineNumber.hashCode());
		result = prime * result + ((prefix == null) ? 0 : prefix.hashCode());
		return result;
	}
	@Override
	public Boolean equals(Object obj) {
		if (this == obj)
		return true;
		if (obj == null)
		return false;
		if (getClass() != obj.getClass())
		return false;
		PhoneNumber other = (PhoneNumber) obj;
		if (areaCode != other.areaCode)
		return false;
		if (lineNumber == null) {
			if (other.lineNumber != null)
			return false;
		} else if (!lineNumber.equals(other.lineNumber))
		return false;
		if (prefix == null) {
			if (other.prefix != null)
			return false;
		} else if (!prefix.equals(other.prefix))
		return false;
		return true;
	}
}

13、數組有沒有 length()方法?String 有沒有 length()方法?

數組沒有 length()方法 ,有 length 的屬性。String 有 length()方法。JavaScript中,獲得字符串的長度是通過 length 屬性得到的,這一點容易和 Java 混淆。歡迎大家關注我的公種浩【程序員追風】,2019年多家公司java面試題整理了1000多道400多頁pdf文檔,文章都會在裏面更新,整理的資料也會放在裏面。

v2-419eef9f92953a664fa3c7b7a9760bfd_hd.png

14、在 Java 中,如何跳出當前的多重嵌套循環?

在最外層循環前加一個標記如 A,然後用 break A;可以跳出多重循環。(Java 中支持帶標籤的 break 和 continue 語句,作用有點類似於 C 和 C++中的 goto 語句,但是就像要避免使用 goto 一樣,應該避免使用帶標籤的 break 和 continue,因爲它不會讓你的程序變得更優雅,很多時候甚至有相反的作用,所以這種語法其實不知道更好)

15、構造器(constructor)是否可被重寫(override)?

構造器不能被繼承,因此不能被重寫,但可以被重載。

16、兩個對象值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對不對?

不對,如果兩個對象 x 和 y 滿足 x.equals(y) == true,它們的哈希碼(hash code)應當相同。Java 對於 eqauls 方法和 hashCode 方法是這樣規定的:

(1)如果兩個對象相同(equals 方法返回 true),那麼它們的 hashCode 值一定要相同;

(2)如果兩個對象的 hashCode 相同,它們並不一定相同。當然,你未必要按照要求去做,但是如果你違背了上述原則就會發現在使用容器時,相同的對象可以出現在 Set 集合中,同時增加新元素的效率會大大下降(對於使用哈希存儲的系統,如果哈希碼頻繁的衝突將會造成存取性能急劇下降)。

補充:關於 equals 和 hashCode 方法,很多 Java 程序都知道,但很多人也就是僅僅知道而已,在 Joshua Bloch 的大作《Effective Java》(很多軟件公司,《Effective Java》、《Java 編程思想》以及《重構:改善既有代碼質量》是 Java程序員必看書籍,如果你還沒看過,那就趕緊去買一本吧)中是這樣介紹equals 方法的:首先 equals 方法必須滿足自反性(x.equals(x)必須返回 true)、

對稱性(x.equals(y)返回 true 時,y.equals(x)也必須返回 true)、傳遞性(x.equals(y)和 y.equals(z)都返回 true 時,x.equals(z)也必須返回 true)和一致性(當 x 和 y 引用的對象信息沒有被修改時,多次調用 x.equals(y)應該得到同樣的返回值),而且對於任何非 null 值的引用 x,x.equals(null)必須返回 false。

實現高質量的 equals 方法的訣竅包括:

(1) 使用==操作符檢查”參數是否爲這個對象的引用”;

(2) 使用 instanceof 操作符檢查”參數是否爲正確的類型”;

(3) 對於類中的關鍵屬性,檢查參數傳入對象的屬性是否與之相匹配;

(4) 編寫完 equals方法後,問自己它是否滿足對稱性、傳遞性、一致性;

(5) 重寫 equals 時總是要重寫 hashCode;

(6)  不要將 equals 方法參數中的 Object 對象替換爲其他的類型,在重寫時不要忘掉@Override 註解。

17、是否可以繼承 String 類?

String 類是 final 類,不可以被繼承。

補充:繼承 String 本身就是一個錯誤的行爲,對 String 類型最好的重用方式是關聯關係(Has-A)和依賴關係(Use-A)而不是繼承關係(Is-A)。

18、當一個對象被當作參數傳遞到一個方法後,此方法可改變這個對象的屬性,並可返回變化後的結果,那麼這裏到底是值傳遞還是引用傳遞?

是值傳遞。Java 語言的方法調用只支持參數的值傳遞。當一個對象實例作爲一個參數被傳遞到方法中時,參數的值就是對該對象的引用。對象的屬性可以在被調用過程中被改變,但對對象引用的改變是不會影響到調用者的。C++和 C#中可以通過傳引用或傳輸出參數來改變傳入的參數的值。在 C#中可以編寫如下所示的代碼,但是在 Java 中卻做不到。

using System;
namespace CS01 {
	class Program {
		public static void swap(ref int x, ref int y) {
			int temp = x;
			x = y;
			y = temp;
		}
		public static void Main (string[] args) {
			int a = 5, b = 10;
			swap (ref a, ref b);
			// a = 10, b = 5;
			Console.WriteLine ("a = {0}, b = {1}", a, b);
		}
	}
}

說明:Java 中沒有傳引用實在是非常的不方便,這一點在 Java 8 中仍然沒有得到改進,正是如此在 Java 編寫的代碼中才會出現大量的 Wrapper 類(將需要通過方法調用修改的引用置於一個 Wrapper 類中,再將 Wrapper 對象傳入方法),這樣的做法只會讓代碼變得臃腫,尤其是讓從 C 和 C++轉型爲 Java 程序員的開發者無法容忍。

19、String 和 StringBuilder、StringBuffer 的區別?

Java 平臺提供了兩種類型的字符串:String 和 StringBuffer/StringBuilder,它們可以儲存和操作字符串。其中 String 是隻讀字符串,也就意味着 String 引用的字符串內容是不能被改變的。而 StringBuffer/StringBuilder 類表示的字符串對象可以直接進行修改。StringBuilder 是 Java 5 中引入的,它和 StringBuffer 的方法完全相同,區別在於它是在單線程環境下使用的,因爲它的所有方面都沒有被synchronized 修飾,因此它的效率也比 StringBuffer 要高。

面試題 1 - 什麼情況下用+運算符進行字符串連接比調用

StringBuffer/StringBuilder 對象的 append 方法連接字符串性能更好?

面試題 2 - 請說出下面程序的輸出。

class StringEqualTest {
	public static void main(String[] args) {
		String s1 = "Programming";
		String s2 = new String("Programming");
		String s3 = "Program";
		String s4 = "ming";
		String s5 = "Program" + "ming";
		String s6 = s3 + s4;
		System.out.println(s1 == s2);
		System.out.println(s1 == s5);
		System.out.println(s1 == s6);
		System.out.println(s1 == s6.intern());
		System.out.println(s2 == s2.intern());
	}
}

補充:解答上面的面試題需要清除兩點:

(1)String 對象的 intern 方法會得到字符串對象在常量池中對應的版本的引用(如果常量池中有一個字符串與 String 對象的 equals 結果是 true),如果常量池中沒有對應的字符串,則該字符串將被添加到常量池中,然後返回常量池中字符串的引用;

(2)字符串的+操作其本質是創建了 StringBuilder 對象進行 append 操作,然後將拼接後的 StringBuilder 對象用toString 方法處理成 String 對象,這一點可以用 javap -c StringEqualTest.class命令獲得 class 文件對應的 JVM 字節碼指令就可以看出來。

20、重載(Overload)和重寫(Override)的區別。重載的方法能否根據返回類型進行區分?

方法的重載和重寫都是實現多態的方式,區別在於前者實現的是編譯時的多態性,而後者實現的是運行時的多態性。重載發生在一個類中,同名的方法如果有不同的參數列表(參數類型不同、參數個數不同或者二者都不同)則視爲重載;重寫發生在子類與父類之間,重寫要求子類被重寫方法與父類被重寫方法有相同的返回類型,比父類被重寫方法更好訪問,不能比父類被重寫方法聲明更多的異常(里氏代換原則)。重載對返回類型沒有特殊的要求。

面試題:華爲的面試題中曾經問過這樣一個問題 - “爲什麼不能根據返回類型來區分重載”,快說出你的答案吧!

最後

歡迎大家一起交流,喜歡文章記得點個贊喲,感謝支持!

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