在 Java 類中定義 toString 方法(學(xué)習(xí) Java 編程語(yǔ)言 050)

在 Object 中還有一個(gè)重要的 toString 方法睬关,它會(huì)返回表示對(duì)象值的一個(gè)字符串诱担。下面是一個(gè)典型的例子。Point 類的 toString方法將返回下面這樣的字符串:
?java.awt.Point[x=10电爹,y=20]

絕大多數(shù)(但不是全部)的 toString 方法都遵循這樣的格式:類的名字蔫仙,隨后是一對(duì)方括號(hào)括起來(lái)的字段值。下面是 Employee 類中的 toString 方法的實(shí)現(xiàn):

public class Employee {
    private String name;
    private double salary;
    private LocalDate hireDay;

    ...
    @Override
    public String toString() {
        return "Employee[name=" + name +
            ",salary=" + salary +
            ",hireDay=" + hireDay + "]";
    }
}

實(shí)際上丐箩,還可以設(shè)計(jì)得更好一些摇邦。最好通過(guò)調(diào)用 getClass().getName() 獲得類名的字符串,而不要將類名硬編碼寫(xiě)到 toString 方法中屎勘。

public class Employee {
    private String name;
    private double salary;
    private LocalDate hireDay;

    ...
    @Override
    public String toString() {
        return getClass().getName() + "[name=" + name +
                ",salary=" + salary +
                ",hireDay=" + hireDay + "]";
    }
}

這樣的 toString 方法也可以由子類調(diào)用施籍。

設(shè)計(jì)子類的程序員應(yīng)該定義自己的 toString 方法,并加入子類的字段概漱。如果超類使用了 getClass().getName()丑慎,那么子類只要調(diào)用 super.toString() 就可以了。例如,下面是 Manager 類中的 toString 方法:

public class Manager extends Employee {
    private double bonus;

    ...
    @Override
    public String toString() {
        return super.toString() + 
            "[bonus=" + bonus + "]";
    }
}

現(xiàn)在立哑,Manager 對(duì)象將打印輸出如下所示的內(nèi)容:
?Manager[name=...,salary=...,hireDay=...] [bonus=...]

隨處可見(jiàn) toString 方法的主要原因是:只要對(duì)象與一個(gè)字符串通過(guò)操作符 “+” 連接起來(lái)夜惭,Java 編譯器就會(huì)自動(dòng)地調(diào)用 toString 方法來(lái)獲得這個(gè)對(duì)象的字符串描述。

提示: 可以不寫(xiě) x.toString()铛绰,而寫(xiě)作 "" + x诈茧。這條語(yǔ)句將一個(gè)空串與 x 的字符串表示(也就是 x.toString())相連接。與 toString 不同的是捂掰,即使 x 是基本類型敢会,這條語(yǔ)句照樣能夠執(zhí)行。

如果 x 是一個(gè)任意對(duì)象这嚣,并調(diào)用
?System.out.println(x)
println 方法就會(huì)簡(jiǎn)單地調(diào)用 x.toString()鸥昏,并打印輸出得到的字符串。

Object 類定義了 toString 方法姐帚,可以打印對(duì)象的類名和散列碼吏垮。例如,調(diào)用:
?System.out.println(System.out);
將輸出:
?java.io.PrintStream@7852e922
得到這樣的結(jié)果原因是 PrintStream 類的設(shè)計(jì)者沒(méi)有覆蓋 toString() 方法罐旗。

警告: 令人煩惱的是膳汪,數(shù)組繼承了 Object 類的 toString 方法,更有甚者九秀,數(shù)組類型將采用一種古老的格式打印遗嗽。例如:
?int[] luckyNumger = {2, 3, 5, 7, 11, 13}
?String s = "" + luckyNumger;
會(huì)生成字符串 “[I@52af6cff”(前綴 [I 表明是一個(gè)整型數(shù)組)。補(bǔ)救的方法是調(diào)用靜態(tài)方法 Arrays.toString鼓蜒。代碼:
?String s = Arrays.toString(luckyNumger);
將生成字符串:
?[2, 3, 5, 7, 11, 13]痹换。
要想打印多維數(shù)組(即,數(shù)組的數(shù)組)都弹,則需要調(diào)用 Arrays.deepToString 方法娇豫。

toString 方法是一種非常有用的調(diào)試工具。在標(biāo)準(zhǔn)類庫(kù)中缔杉,許多類都定義了 toString 方法锤躁,以便用戶能夠獲得一些有關(guān)對(duì)象狀態(tài)的有用信息。

像下面這樣顯示日志信息非常有益:
?System.out.println("Current position = " + position);

提示: 強(qiáng)烈建議為自定義的每一個(gè)類增加 toString 方法或详。這樣做不僅自己受益系羞,所有使用這個(gè)類的程序員也會(huì)從這個(gè)日志記錄支持中受益匪淺。

java.long.Object 1.0

  • Class getClass()

    返回包含對(duì)象信息的類對(duì)象霸琴。

  • boolean equals(Object otherObject)

    比較兩個(gè)對(duì)象是否相等椒振,如果兩個(gè)對(duì)象指向同一塊存儲(chǔ)區(qū)域,方法返回 true梧乘;否則方法返回 false澎迎。要在自定義的類中覆蓋這個(gè)方法庐杨。

  • String toString()

    返回表示對(duì)象值的字符串。要在自定義的類中覆蓋這個(gè)方法夹供。

java.lang.Class 1.0

  • String getName()

    返回這個(gè)類的名字灵份。

  • Class getSuperclass()

    以 Class 對(duì)象的形式返回這個(gè)類的超類信息。

示例代碼

import java.time.LocalDate;
import java.util.Objects;
/**
 * 
 * @author bpx
 * @version 1.0.0
 * @since 1.7.1
 * 
 * 
 */
public class Employee {
    // 姓名
    private String name;
    // 薪資
    private double salary;
    // 認(rèn)知日期
    private LocalDate hireDay;

    /**
     * Employee 構(gòu)造方法
     * @param name 員工姓名
     * @param salary 員工工資
     * @param year 入職年
     * @param month 入職月
     * @param day 入職日
     */
    public Employee(String name, double salary, int year, int month, int day) {
        Objects.requireNonNull(name, "The name cannot be null");
        this.name = name;
        this.salary = salary;
        hireDay = LocalDate.of(year, month, day);
    }

    /**
     * 獲得員工姓名
     * @return 用戶姓名
     */
    public String getName() {
        return name;
    }
    /**
     * 獲得員工工資
     * @return 工資
     */
    public double getSalary() {
        return salary;
    }
    /**
     * 獲得用戶入職日期
     * @return 入職日期
     * @throws NullPointerException
     */
    public LocalDate getHireDay() {
        return hireDay;
    }
    /**
     * 增加工資
     * @param byPercent 百分比
     */
    public void raiseSalary(double byPercent) {
        double raise = salary * byPercent / 100;
        salary += raise;
    }

    @Override
    public boolean equals(Object otherObject)
    {
        // a quick test to see if the objects are identical
        if (this == otherObject) return true;

        // must return false if the explicit parameter is null
        if (otherObject == null) return false;

        // if the classes don't match, they can't be equal
        if (getClass() != otherObject.getClass())
            return false;
        
        // now we know otherObject is a non-null Employee
        Employee other = (Employee) otherObject;

        // test whether the fields have identical values
        return Objects.equals(name, other.name)
                && salary == other.salary
                && Objects.equals(hireDay, other.hireDay);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, salary, hireDay);
    }
    @Override
    public String toString() {
        String str = "%s[name=%s, salary=%.2f, hireDay=%s]";
        return String.format(str, getClass().getName(), name, salary, hireDay);
    }
}
import java.util.Objects;

public class Manager extends Employee {

    private double bonus;

    public Manager(String name, double salary, int year, int month, int day) {
        super(name, salary, year, month, day);
        this.bonus = 0;
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }

    public double getSalary() {
        double baseSalary = super.getSalary();
        return baseSalary + bonus;
    }

    @Override
    public boolean equals(Object otherObject)
    {
        if (!super.equals(otherObject)) return false;
        Manager other = (Manager) otherObject;
        // super.equals checked that this and otherObject belong to the same class
        return bonus == other.bonus;
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), bonus);
    }
 
    @Override
    public String toString() {
        return super.toString() + 
            "[bonus=" + bonus + "]";
    }
}
public class Testing {

    public static void main(String[] args) {
        Employee alicel = new Employee("Alice Adams" , 75000 , 1987, 12, 15);
        Employee alice2 = alicel;
        Employee alice3 = new Employee("Alice Adams", 75000, 1987, 12, 15);
        Employee bob = new Employee("Bob Brandson" , 50000, 1989, 10, 1);
        
        System.out.println("alicel == alice2: " + (alicel == alice2));        
        System.out.println("alicel == alice3: " + (alicel == alice3)) ;        
        System.out.println("alicel.equals(alice3): " + alicel.equals(alice3));        
        System.out.println("alicel.equals(bob): " + alicel.equals(bob)) ;        
        System.out.println("bob.toString(): " + bob);
        
        Manager carl = new Manager("Carl Cracker", 80000 , 1987, 12, 15) ;
        Manager boss = new Manager("Carl Cracker", 80000 , 1987, 12, 15) ;
        boss.setBonus(5000);
        
        System.out.println("boss.toString(): " + boss);
        System.out.println("carl.equals(boss): " + carl.equals(boss)) ;
        System.out.println("alicel.hashCode(): " + alicel.hashCode()) ;
        System.out.println("alice3.hashCode(): " + alice3.hashCode()) ;
        System.out.println("bob.hashCode(): " + bob.hashCode());
        System.out.println("carl.hashCode(): " + carl.hashCode());
    }
}

輸出:

alicel == alice2: true
alicel == alice3: false
alicel.equals(alice3): true
alicel.equals(bob): false
bob.toString(): com.xiang117.corejava.Employee[name=Bob Brandson, salary=50000.00, hireDay=1989-10-01]
boss.toString(): com.xiang117.corejava.Manager[name=Carl Cracker, salary=80000.00, hireDay=1987-12-15][bonus=5000.0]
carl.equals(boss): false
alicel.hashCode(): -808853550
alice3.hashCode(): -808853550
bob.hashCode(): -624019882
carl.hashCode(): -2004699436
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哮洽,一起剝皮案震驚了整個(gè)濱河市填渠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鸟辅,老刑警劉巖氛什,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異匪凉,居然都是意外死亡枪眉,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門再层,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)贸铜,“玉大人,你說(shuō)我怎么就攤上這事聂受∪裕” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵饺饭,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我职车,道長(zhǎng)瘫俊,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任悴灵,我火速辦了婚禮扛芽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘积瞒。我一直安慰自己川尖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布茫孔。 她就那樣靜靜地躺著叮喳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪缰贝。 梳的紋絲不亂的頭發(fā)上馍悟,一...
    開(kāi)封第一講書(shū)人閱讀 51,258評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音剩晴,去河邊找鬼锣咒。 笑死侵状,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的毅整。 我是一名探鬼主播趣兄,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼悼嫉!你這毒婦竟也來(lái)了艇潭?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤承粤,失蹤者是張志新(化名)和其女友劉穎暴区,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體辛臊,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡仙粱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了彻舰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伐割。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖刃唤,靈堂內(nèi)的尸體忽然破棺而出隔心,到底是詐尸還是另有隱情,我是刑警寧澤尚胞,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布硬霍,位于F島的核電站,受9級(jí)特大地震影響笼裳,放射性物質(zhì)發(fā)生泄漏唯卖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一躬柬、第九天 我趴在偏房一處隱蔽的房頂上張望拜轨。 院中可真熱鬧,春花似錦允青、人聲如沸橄碾。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)法牲。三九已至,卻和暖如春琼掠,著一層夾襖步出監(jiān)牢的瞬間皆串,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工眉枕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恶复,地道東北人怜森。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像谤牡,于是被迫代替她去往敵國(guó)和親副硅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容