起初接觸這個類就覺得這個類很神奇,各種方法的都不會改變其本身,這也容易引起很多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);
}
輸出結果是
這不是沒變化嗎?
後來發現IDEA的小提示:
他說我把這個方法的傳回值忽略了,我看了一下還真是,一般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);
}
輸出結果:
果然就可以了。
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);
}
輸出結果:
這不是又沒變嗎?
根據我們以往的概念,調用方法的時候參數為非基本資料類型的都是引用傳遞,方法裡面改了它的值方法外面跟着動,因為它就是同一個執行個體。但這個BigDecimal好像就是不符合常理。後來查了一下,這個BigDecimal居然是個不可變類。有同學不太了解不可變類是啥?這麼說吧,你可以把它了解為它的所有屬性就是final的,不可改變。是以你調用它的任何方法都不會改變執行個體本身,而是建立一個新的對象。就跟String一樣。
這樣一來都能想的明白了,原來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;
}
結果:
在調用change方法的時候,b對象的确是傳了進去,被形參d指向,這個時候b和d都指向同一個對象,然後我在方法内部把d指向了一個新的對象,但是原來b的指向沒變,是以b始終沒變。
綜上,我們得出如下結論:
1.對不可變類的任何操作都不會改變不可變類本身執行個體,而是創造一個新的執行個體(原來不用的執行個體會在GC時被回收)
2.不可變類作為參數傳入方法内,方法内對不可變類的操作不會對方法外部造成影響。