天天看點

java BigDecimal中的坑們

起初接觸這個類就覺得這個類很神奇,各種方法的都不會改變其本身,這也容易引起很多BUG。

比如 BigDecimal.setScale()這個方法,正常了解調用這個方法以後原來的對象的精度就被改變了,但事實并非如此:

public void test5() {
        BigDecimal decimal = BigDecimal.valueOf(3.333333333);
        System.out.println(decimal);
        decimal.setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println(decimal);
    }
           

輸出結果是  

java BigDecimal中的坑們

這不是沒變化嗎?

java BigDecimal中的坑們

後來發現IDEA的小提示:

java BigDecimal中的坑們

他說我把這個方法的傳回值忽略了,我看了一下還真是,一般POJO的set方法都是無傳回值的,這玩意特立獨行有個BigDecimal的傳回值。然後我們把代碼改成這樣:

public void test5() {
        BigDecimal decimal = BigDecimal.valueOf(3.333333333);
        System.out.println(decimal);
        BigDecimal decimal2 = decimal.setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println(decimal2);
    }
           

輸出結果:

java BigDecimal中的坑們

果然就可以了。

BigDecimal果然是一個奇葩的類,天真的我以為事情到此就結束了,直到有一天,寫的功能又出問題了

事情大概是這樣的:除了改變了它的精度以外,我還在别的方法裡面改了它的值:

public void test5() {
        BigDecimal decimal = BigDecimal.valueOf(3.333333333);
        System.out.println(decimal);
        BigDecimal decimal2 = decimal.setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println(decimal2);
        change(decimal);
        System.out.println(decimal);
    }

    private void change(BigDecimal bigDecimal) {
        bigDecimal = bigDecimal.multiply(BigDecimal.TEN);
    }
           

輸出結果:

java BigDecimal中的坑們

這不是又沒變嗎?

java BigDecimal中的坑們

根據我們以往的概念,調用方法的時候參數為非基本資料類型的都是引用傳遞,方法裡面改了它的值方法外面跟着動,因為它就是同一個執行個體。但這個BigDecimal好像就是不符合常理。後來查了一下,這個BigDecimal居然是個不可變類。有同學不太了解不可變類是啥?這麼說吧,你可以把它了解為它的所有屬性就是final的,不可改變。是以你調用它的任何方法都不會改變執行個體本身,而是建立一個新的對象。就跟String一樣。

java BigDecimal中的坑們

這樣一來都能想的明白了,原來setScale方法也是這個解釋。但是為啥我在别的方法裡面改這個對象改不了了呢?

我們這樣了解一下:

public void test6() {
        String a = new String("ori");
        BigDecimal b = BigDecimal.TEN;
        System.out.println(a);
        System.out.println(b);
    }

    private void change(String c, BigDecimal d) {
        c = new String("hhh");
        d = BigDecimal.ZERO;
    }
           

結果:

java BigDecimal中的坑們

在調用change方法的時候,b對象的确是傳了進去,被形參d指向,這個時候b和d都指向同一個對象,然後我在方法内部把d指向了一個新的對象,但是原來b的指向沒變,是以b始終沒變。

綜上,我們得出如下結論:

1.對不可變類的任何操作都不會改變不可變類本身執行個體,而是創造一個新的執行個體(原來不用的執行個體會在GC時被回收)

2.不可變類作為參數傳入方法内,方法内對不可變類的操作不會對方法外部造成影響。