阿里巴巴Java開發手冊:編程規約.OOP

2.【強制】所有的覆寫方法,必須加@Override註解。

說明:getObject()與get0bject()的問題。一個是字母的O,一個是數字的0,加@Override可以準確判斷是否覆蓋成功,避免外形太像導致覆寫失敗。另外,如果在抽象類中對方法簽名進行修改,其實現類會馬上編譯報錯。

重寫發生在運行期,是子類對父類的允許訪問的方法的實現過程進行重新編寫。返回值類型、方法名、參數列表必須相同,拋出的異常範圍小於等於父類,訪問修飾符範圍大於等於父類,即要滿足里氏替換原則。

如果父類方法訪問修飾符爲 private/final/static 則子類就不能重寫該方法,但是被static修飾的方法能夠被再次聲明。

構造方法無法被重寫。

3.【強制】相同參數類型,相同業務含義,纔可以使用Java的可變參數,避免使用Object。

正例:

public List<User> listUsers(String type, Long... ids) {...}

說明:可變參數必須放置在參數列表的最後。(提倡同學們儘量不用可變參數編程)

java 可變參數是1.5版本的新特性,也就是說用戶若是想定義一個方法,但是在此之前並不知道以後要用的時候想傳幾個參數進去,可以在方法的參數列表中寫參數類型或者數組名,然後在方法內部直接用操作數組的方式操作。適用於參數個數不確定,類型確定的情況。

可參考文章:https://blog.csdn.net/w605283073/article/details/91902705

4.【強制】外部正在調用或者二方庫依賴的接口,不允許修改方法簽名,避免對接口調用方產生影響。接口過時必須加@Deprecated註解,並清晰地說明採用的新接口或者新服務是什麼。

說明:方法簽名是方法名+參數類型,比如以下這個方法

public double calculateAnswer(double wingSpan, int numberOfEngines,
                              double length, double grossTons) {
    //do the calculation here
}

方法簽名就是calculateAnswer(double, int, double, double),如果修改了,調用方處的代碼必然會報錯。

@Deprecated註解,若某類或某方法加上該註解之後,表示此方法或類不再建議使用,調用時也會出現刪除線,但並不代表不能用,只是說不推薦使用,因爲還有更好的方法可以調用。不將原來的方法直接刪除是因爲可能在很多地方需要調用他,刪除帶來的工作量太大,只能使用該註解說明過時,讓之後的開發者使用新的方法。

6.【強制】Object的equals方法容易拋空指針異常,應使用常量或確定有值的對象來調用equals。

正例:“test”.equals(object);
反例:object.equals(“test”);
說明:推薦使用java.util.Objects#equals(JDK7引入的工具類)
方法內部是這樣

// 1. Objects.equals(Object a, Object b)
public static boolean equals(Object a, Object b) {
    return (a == b) || (a != null && a.equals(b));
}

// 2. Object.equals(Object obj)
public boolean equals(Object obj) {
  return (this == obj);
}

首先是對象的引用判斷,其次就是調用對象自身的equals方法來比較,如果對象類型沒有重寫equals的話,就會調用Object的equals方法(仍然是對象的引用比較),並且還考慮了null的問題。

該工具類中還有hashCode()和toString()方法,也很簡單易用

8.關於基本數據類型與包裝數據類型的使用標準如下:

1) 【強制】所有的POJO類屬性必須使用包裝數據類型。

2) 【強制】RPC方法的返回值和參數必須使用包裝數據類型。

3) 【推薦】所有的局部變量使用基本數據類型。

正例:數據庫的查詢結果可能是null,因爲自動拆箱,用基本數據類型接收有NPE風險。

反例:比如顯示成交總額漲跌情況,即正負x%,x爲基本數據類型,調用的RPC服務,調用不成功時,返回的是默認值,頁面顯示爲0%,這是不合理的,應該顯示成中劃線。所以包裝數據類型的null值,能夠表示額外的信息,如:遠程調用失敗,異常退出。

說明:POJO類屬性沒有初值是提醒使用者在需要使用時,必須自己顯式地進行賦值,任何NPE(NullPointException)問題,或者入庫檢查,都由使用者來保證。這點我們需要自己注意,在平常的開發中很少使用包裝數據類型,大部分是基本數據類型,需要改正。

10.【強制】序列化類新增屬性時,請不要修改serialVersionUID字段,避免反序列失敗;如果完全不兼容升級,避免反序列化混亂,那麼請修改serialVersionUID值。

說明:注意serialVersionUID不一致會拋出序列化運行時異常。

serialVersionUID適用於Java的序列化機制。簡單來說,Java的序列化機制是通過判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地相應實體類的serialVersionUID進行比較,如果相同就認爲是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常,即是InvalidCastException。

serialVersionUID有兩種顯示的生成方式:

一是默認的1L,比如:

private static final long serialVersionUID = 1L; 

二是根據包名,類名,繼承關係,非私有的方法和屬性,以及參數,返回值等諸多因子計算得出的一個64位的哈希字段。基本上計算出來的這個值是唯一的。比如:

private static final long  serialVersionUID = xxxxL; 

這種情況下,如果Class文件(類名,方法名等)沒有發生變化(增加空格,換行,增加註釋等等),就算再編譯多次,serialVersionUID也不會變化的,此種方式是不兼容的。

18.【推薦】循環體內,字符串的連接方式,使用StringBuilder的append方法進行擴展。

反例:

String str = "start";
for (int i = 0; i < 100; i++) {
    str = str + "hello";
}

說明:上例中,反編譯出的字節碼文件顯示每次循環都會new出一個StringBuilder對象,然後進行append操作,最後通過toString方法返回String對象,造成內存資源浪費。

String是不可變的,因爲使用final關鍵字修飾字符數組來保存字符串,StringBuilder與StringBuffer 都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數組保存字符串char[]value,但是沒有用final關鍵字修飾,所以這兩種對象都是可變的。jvm會將string的連接優化成stringbuilder的append,但是會消耗資源,在循環中每次都產生一個stringbuilder。

可見:
https://www.cnblogs.com/rjhlovelife/archive/2018/06/09/9159953.html

20.【推薦】慎用Object的clone方法來拷貝對象。 說明:對象的clone方法默認是淺拷貝,若想實現深拷貝需要重寫clone方法實現域對象的深度遍歷式拷貝。

說明:針對引用類型,淺拷貝只複製指向某個對象的指針,而不復制對象本身,新舊對象還是共享同一塊內存,修改新對象會導致原對象也改變。但深拷貝會另外創造一個一模一樣的對象,新對象跟原對象不共享內存,修改新對象不會改到原對象。
深拷貝可以通過序列化和遞歸重寫clone方法實現。

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