在Java中,負數的絕對值不一定是正數!

作者 l Hollis
來源 l Hollis(ID:hollischuang)
絕對值是指一個數在數軸上所對應點到原點的距離,所以,在數學領域,正數的絕對值是這個數本身,負數的絕對值應該是他的相反數。
這幾乎是每個人都知道的。
在Java中,想要獲得有個數字的絕對值,可以使用 java.lang.Math 中的 abs 方法,這個類共有4個重載的abs方法,分別是:

 public static int abs(int a) {

        return (a < 0) ? -a : a;

    }


    public static long abs(long a) {

        return (a < 0) ? -a : a;

    }


    public static float abs(float a) {

        return (a <= 0.0F) ? 0.0F - a : a;

    }


    public static double abs(double a) {

        return (a <= 0.0D) ? 0.0D - a : a;

    }

以上4個方法分別返回int、long、float、double類型的絕對值,方法裏面的邏輯也簡單,無非就是整數直接返回,負數取相反數返回

所以,基於以上所有的知識,我們經常會直接使用Math.abs來對一個數字取絕對值。
在我們的代碼中,也有很多這樣的例子。
比如,我們需要用訂單號做分庫分表,但是訂單號是字符串類型,所以,我們就需要取得這個字符換的hashCode,因爲hashCode可能是負數,所以然後再對hashCode取絕對值,再用這個值去對分表數取模:

    
    
    
  Math.abs(orderId.hashCode()) % 1024;

但是,上面這個邏輯是有問題的!!!

因爲在極特殊情況下,上面的代碼會得到一個負數的值。
這個極特殊情況下就是當hashCode是Integer.MIN_VALUE,即整數能表達的最小值的時候,可以代碼驗證下:

  public static void main(String[] args) {

      System.out.println(Math.abs(Integer.MIN_VALUE));

  }

執行以上代碼,得到的結果是:

  -2147483648

很明顯,這是個負數!!!

爲什麼會這樣呢?
這要從Integer的取值範圍說起,int的取值範圍是-2^31 —— (2^31) - 1,即-2147483648 至 2147483647
那麼,當我們使用abs取絕對值時候,想要取得-2147483648的絕對值,那應該是2147483648。
但是,2147483648大於了2147483647,即超過了int的取值範圍。這時候就會發生越界。

2147483647用二進制的補碼錶示是:

01111111 11111111 11111111 11111111 

這個數 +1 得到:

10000000 00000000 00000000 00000000 

這個二進制就是-2147483648的補碼。

雖然,這種情況發生的概率很低,只有當要取絕對值的數字是-2147483648的時候,得到的數字還是個負數。
那麼,如何解決這個問題呢?
既然是以爲越界了導致最終結果變成負數,那就解決越界的問題就行了,那就是在取絕對值之前,把這個int類型轉成long類型,這樣就不會出現越界了。
如,前面我們的分表邏輯修改爲

 Math.abs((long)orderId.hashCode()) % 1024

就萬無一失了。

大家可以執行下以下代碼:

public static void main(String[] args) {

      System.out.println(Math.abs((long)Integer.MIN_VALUE));

  }

得到的結果就是:

 2147483648

以上,就是今天要介紹的知識點了。

但是,一定要記得,對long類型取絕對值其實也可能存在這個情況哦!只不過發生的概率就更低了,但是隻要他存在,就有可能發生哦!

    
    
    

往期推薦

絕,Java 中創建對象的 5 種方法!


SpringBoot 優雅的參數效驗!


MyBatis 的執行流程,學廢了!




本文分享自微信公衆號 - Java中文社羣(javacn666)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

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