在前面幾天,我們學會了用類別親手捏出實體。今天滿心歡喜地在主程式寫下這一行:
Person p1 = new Person("予安", 20);
System.out.println(p1); // 印出這個人!
你原本期待終端機會吐出「姓名:予安,年齡:20」,結果螢幕卻噴出一串外星咒語:
Person@6d06d69c這是什麼亂碼天書?電腦中毒了嗎?
其實電腦沒壞,它只是在公事公辦,執行全 Java 宇宙所有物件的大始祖 Object 類別所定下的家規!
老祖宗根本看不透你:老祖宗Object 是千百年前就被寫死的祖先藍圖,它怎麼可能預知未來的工程師會在 Person 裡面放 name?既然看不透每個子孫肚子裡裝了什麼,它就只能公事公辦,回傳你家門牌號碼(類別名稱 + @ + 記憶體雜湊碼)。靠覆寫(@Override)改寫命運:拒絕繼承火星文!
如果不想世世代代印出來都是「Person@6d06d69c」這種外星編號,就必須覆寫(@Override)把大括號裡的命運改寫成人話!
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 撕掉老祖宗的火星文版,換成自己想講的人話!
@Override
public String toString() {
return "姓名: " + this.name + ", 年齡: " + this.age;
}
}
有了這張全新講稿,下次你再放心寫下 System.out.println(p1);,Java 順著地址一查,發現你已經改寫過 toString(),終端機就會乖乖印出清晰易懂的:
姓名: 予安, 年齡: 20
一句話記住:
物件進印表機一律自動找 .toString();不想看老祖宗吐記憶體門牌,就用 @Override 逼它講人話!
除了印出物件會踩雷,物件導向另一個著名的「新手修羅場」,就是拿兩個物件來比對:
Person a = new Person("小明", 20);
Person b = new Person("小明", 20);
System.out.println(a == b); // 輸出 false!
System.out.println(a.equals(b)); // 輸出也是 false!
明明兩張卡片上印的姓名、年齡分毫不差,為什麼電腦給出false?
== 是最無情的戶籍員(只認門牌):new 兩次,代表在記憶體裡開了兩個空間。a 住在 101 號房,b 住在 204 號房。== 只關心一件事:「你們兩個是不是同一個空間?」,地址不同回傳 false!
沒改寫的 equals(),底層根本就是換皮的 ==:
老祖宗看不透你肚子裡裝了姓名還是年齡,所以對相等的定義除非是同一個記憶體空間,否則不算相等。
教電腦認人:自己動手覆寫 equals()
在人類的世界裡,只要身分證上的姓名與年齡相同,我們就認定是同一人。如果想讓電腦也懂這個道理,就得親自手動覆寫 equals():
@Override
public boolean equals (Object obj) {
為了讓任何東西都能當成參數送進來,老祖宗希望能比對全天下任何東西就規定參數型別必須是宇宙最大容器:Object obj。不管對方是貓、狗、還是人,老祖宗的箱子容納一切,只要能傳進來就一定是物件
// 1.安檢檢查:掃描丟進來的未知物件 obj,確認:「你的真面目到底是不是 Person?」如果不是(例如丟進來一隻狗或一顆蘋果)直接判定比對失敗
// 先檢查送進來的包裹是不是 Person;是就換成 Person 標籤someone
if (obj instanceof Person someone) {
// 2. 不轉型的下場:雖然你心裡明知他是人,但此時他身上的標籤依然是 Object obj(
「它的標籤是 Object,老祖宗身上根本沒有 age 這顆按鈕,obj.age會亮紅線!」
為什麼要向下轉型(拿掉封印):
換成 Person someone 。貼上 Person 的標籤,電腦才准許someone.age 來跟自己比對!
return this.age == someone.age;
}
// 如果對方是一顆蘋果或根本是 null,連比都不用比,直接判不相等!
return false;
}