這裡會分享一些出現頻率極其極其高的面試題,初定周更一篇,什麼時候更完什麼時候停止。
Github地址:github.com/Snailclimb/…
一 Java中的值傳遞和引用傳遞(非常重要)
首先要明確的是:“物件傳遞(陣列、類、介面)是引用傳遞,原始型別資料(整型、浮點型、字元型、布林型)傳遞是值傳遞。”
那麼什麼是值傳遞和應用傳遞呢?
值傳遞是指物件被值傳遞,意味著傳遞了物件的一個副本,即使副本被改變,也不會影響源物件。(因為值傳遞的時候,實際上是將實參的值複製一份給形參。)
引用傳遞是指物件被引用傳遞,意味著傳遞的並不是實際的物件,而是物件的引用。因此,外部對引用物件的改變會反映到所有的物件上。(因為引用傳遞的時候,實際上是將實參的地址值複製一份給形參。)
有時候面試官不是單純問你“Java中是值傳遞還是引用傳遞”是什麼啊,騷年?而是給出一個例子,然後讓你寫出答案,這種也常見在筆試題目中!所以,非常重要了,請看下面的例子:
值傳遞和應用傳遞例項
1. 值傳遞
public static void main(String[] args) {
int num1 = 10;
int num2 = 20;
swap(num1, num2);
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
}
public static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
System.out.println("a = " + a);
System.out.println("b = " + b);
}
複製程式碼
結果:
a = 20
b = 10
num1 = 10
num2 = 20
複製程式碼
解析:
在swap方法中,a、b的值進行交換,並不會影響到num1、num2。因為,a、b中的值,只是從num1、num2的複製過來的。 也就是說,a、b相當於num1、num2的副本,副本的內容無論怎麼修改,都不會影響到原件本身。
2. 引用傳遞
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
change(arr);
System.out.println(arr[0]);
}
public static void change(int[] array) {
//將陣列的第一個元素變為0
array[0] = 0;
}
複製程式碼
結果:
1
0
複製程式碼
解析:
無論是主函式,還是change方法,操作的都是同一個地址值對應的陣列。 。因此,外部對引用物件的改變會反映到所有的物件上。
一些特殊的例子
1. StringBuffer型別傳遞
// 測試引用傳遞:StringBuffer
@org.junit.Test
public void method1() {
StringBuffer str = new StringBuffer("公眾號:Java面試通關手冊");
System.out.println(str);
change1(str);
System.out.println(str);
}
public static void change1(StringBuffer str) {
str = new StringBuffer("abc");//輸出:“公眾號:Java面試通關手冊”
//str.append("歡迎大家關注");//輸出:公眾號:Java面試通關手冊歡迎大家關注
//str.insert(3, "(程式設計)");//輸出:公眾號(程式設計):Java面試通關手冊
}
複製程式碼
結果:
公眾號:Java面試通關手冊
公眾號:Java面試通關手冊
複製程式碼
解析:
很多要這個時候要問了:StringBuffer建立的明明也是物件,那為什麼輸出結果依然是原來的值呢?
因為在change1
方法內部我們是新建了一個StringBuffer物件,所以str
指向了另外一個地址,相應的操作也同樣是指向另外的地址的。
那麼,如果將change1
方法改成如下圖所示,想必大家應該知道輸出什麼了,如果你還不知道,那可能就是我講的有問題了,我反思(開個玩笑,上面程式中已經給出答案):
public static void change1(StringBuffer str) {
str.append("歡迎大家關注");
str.insert(3, "(程式設計)");
}
複製程式碼
2. String型別傳遞
// 測試引用傳遞:Sring
@org.junit.Test
public void method2() {
String str = new String("公眾號:Java面試通關手冊");
System.out.println(str);
change2(str);
System.out.println(str);
}
public static void change2(String str) {
// str="abc"; //輸出:公眾號:Java面試通關手冊
str = new String("abc"); //輸出:公眾號:Java面試通關手冊
}
複製程式碼
結果:
公眾號:Java面試通關手冊
公眾號:Java面試通關手冊
複製程式碼
可以看到不論是執行str="abc;"
還是str = new String("abc");
str的輸出的值都不變。
按照我們上面講“StringBuffer型別傳遞”的時候說的,str="abc;"
應該會讓str的輸出的值都不變。為什麼呢?因為String在建立之後是不可變的。
3. 一道類似的題目
下面的程式輸出是什麼?
public class Demo {
public static void main(String[] args) {
Person p = new Person("張三");
change(p);
System.out.println(p.name);
}
public static void change(Person p) {
Person person = new Person("李四");
p = person;
}
}
class Person {
String name;
public Person(String name) {
this.name = name;
}
}
複製程式碼
很明顯仍然會輸出張三
。因為change
方法中重新建立了一個Person
物件。
那麼,如果把change
方法改為下圖所示,輸出結果又是什麼呢?
public static void change(Person p) {
p.name="李四";
}
複製程式碼
答案我就不說了,我覺得大家如果認真看完上面的內容之後應該很很清楚了。
二 ==與equals(重要)
== : 它的作用是判斷兩個物件的地址是不是相等。即,判斷兩個物件是不是同一個物件。(基本資料型別==比較的是值,引用資料型別==比較的是記憶體地址)
equals() : 它的作用也是判斷兩個物件是否相等。但它一般有兩種使用情況:
- 情況1:類沒有覆蓋equals()方法。則通過equals()比較該類的兩個物件時,等價於通過“==”比較這兩個物件。
- 情況2:類覆蓋了equals()方法。一般,我們都覆蓋equals()方法來兩個物件的內容相等;若它們的內容相等,則返回true(即,認為這兩個物件相等)。
舉個例子:
public class test1 {
public static void main(String[] args) {
String a = new String("ab"); // a 為一個引用
String b = new String("ab"); // b為另一個引用,物件的內容一樣
String aa = "ab"; // 放在常量池中
String bb = "ab"; // 從常量池中查詢
if (aa == bb) // true
System.out.println("aa==bb");
if (a == b) // false,非同一物件
System.out.println("a==b");
if (a.equals(b)) // true
System.out.println("aEQb");
if (42 == 42.0) { // true
System.out.println("true");
}
}
}
複製程式碼
說明:
- String中的equals方法是被重寫過的,因為object的equals方法是比較的物件的記憶體地址,而String的equals方法比較的是物件的值。
- 當建立String型別的物件時,虛擬機器會在常量池中查詢有沒有已經存在的值和要建立的值相同的物件,如果有就把它賦給當前引用。如果沒有就在常量池中重新建立一個String物件。
三 hashCode與equals(重要)
面試官可能會問你:“你重寫過 hashcode 和 equals 麼,為什麼重寫equals時必須重寫hashCode方法?”
hashCode()介紹
hashCode() 的作用是獲取雜湊碼,也稱為雜湊碼;它實際上是返回一個int整數。這個雜湊碼的作用是確定該物件在雜湊表中的索引位置。hashCode() 定義在JDK的Object.java中,這就意味著Java中的任何類都包含有hashCode() 函式。
雜湊表儲存的是鍵值對(key-value),它的特點是:能根據“鍵”快速的檢索出對應的“值”。這其中就利用到了雜湊碼!(可以快速找到所需要的物件)
為什麼要有hashCode
我們以“HashSet如何檢查重複”為例子來說明為什麼要有hashCode:
當你把物件加入HashSet時,HashSet會先計算物件的hashcode值來判斷物件加入的位置,同時也會與其他已經加入的物件的hashcode值作比較,如果沒有相符的hashcode,HashSet會假設物件沒有重複出現。但是如果發現有相同hashcode值的物件,這時會呼叫equals()方法來檢查hashcode相等的物件是否真的相同。如果兩者相同,HashSet就不會讓其加入操作成功。如果不同的話,就會重新雜湊到其他位置。(摘自我的Java啟蒙書《Head fist java》第二版)。這樣我們就大大減少了equals的次數,相應就大大提高了執行速度。
hashCode()與equals()的相關規定
- 如果兩個物件相等,則hashcode一定也是相同的
- 兩個物件相等,對兩個物件分別呼叫equals方法都返回true
- 兩個物件有相同的hashcode值,它們也不一定是相等的
- 因此,equals方法被覆蓋過,則hashCode方法也必須被覆蓋
- hashCode()的預設行為是對堆上的物件產生獨特值。如果沒有重寫hashCode(),則該class的兩個物件無論如何都不會相等(即使這兩個物件指向相同的資料)
寫在最後
推薦一個自己的開源的後端文件
Java-Guide: Java面試通關手冊(Java學習指南)Java Interview Customs Manual (Java Study Guide)。star:1.4k。
Github地址:github.com/Snailclimb/…
文件定位:一個專門為Java後端工程師準備的開源文件,相信不論你是Java新手還是已經成為一名Java工程師都能從這份文件中收穫到一些東西。
面試相關資源免費分享
Java最新17年面試筆試題+Java面試寶典+簡歷模版就業指導筆記視訊+ Java校招面試 Google面試官親授+Java[BAT]面試必備+2017Google面試官親授 java校招面試
關注微信公眾號“Java面試通關手冊”回覆“面試”即可免費領取!
參考:
如果想要獲取更多我的原創文章以及優質學習資源,歡迎關注我的微信公眾號:"Java面試通關手冊" 。無套路,希望能與您共同進步,互相學習。