一、金融相关金额计算BigDecimal(浮点型经度计算)
浮点型精度损失问题用BigDecimal类型,参数传递字符串类型(把字符串拆成字节数组进行计算);
加(add)减(subtract)乘(multipy)除(divide)绝对值(abs)
package besttest.day01; import org.testng.annotations.Test; import java.math.BigDecimal; public class BigDecimalTest { //加运算,输入都为String类型数值 public BigDecimal add(Object s1,Object s2){ BigDecimal sum=null; try { BigDecimal num1 = new BigDecimal(String.valueOf(s1)); BigDecimal num2 = new BigDecimal(String.valueOf(s2)); sum = num1.add(num2); }catch (Exception e){ e.printStackTrace(); System.out.println("输入字符串有误"); } return sum; } //减运算 public BigDecimal delete(Object a,Object b){ BigDecimal sum = null; try { BigDecimal num1 = new BigDecimal(String.valueOf(a)); BigDecimal num2 = new BigDecimal(String.valueOf(b)); sum = num1.subtract(num2); }catch (Exception e){ e.printStackTrace(); System.out.println("输入数值有误"); } return sum; } //乘法运算multipy() public BigDecimal multipy(Object a,Object b){ BigDecimal sum = null; try { BigDecimal num1 = new BigDecimal(String.valueOf(a)); BigDecimal num2 = new BigDecimal(String.valueOf(b)); sum = num1.multiply(num2); }catch (Exception e){ e.printStackTrace(); System.out.println("输入数值有误"); } return sum; } //除法运算divide() public BigDecimal divide(Object a,Object b){ BigDecimal sum = null; try { BigDecimal num1 = new BigDecimal(String.valueOf(a)); BigDecimal num2 = new BigDecimal(String.valueOf(b)); sum = num1.divide(num2); }catch (Exception e){ e.printStackTrace(); System.out.println("输入数值有误"); } return sum; } public static void main(String[] args) { BigDecimalTest bigDecimal = new BigDecimalTest(); BigDecimal result1 = bigDecimal.add(new BigDecimal("400000000000.0909"),new BigDecimal("909909988899.00")); System.out.println(result1); result1 = bigDecimal.add(4000.099898,1009494.389283444); System.out.println(result1); result1 = bigDecimal.add("333334444.33333","0990993039.999999999"); System.out.println(result1); } //减法测试 @Test public void deleteTest(){ BigDecimalTest bigDecimalTest = new BigDecimalTest(); BigDecimal result1 = bigDecimalTest.delete(999999999.0000,090900.09090099); BigDecimal result2 = bigDecimalTest.delete("99989.99888777","76766666.99"); BigDecimal result3 = bigDecimalTest.delete("989988.878",900000.00); System.out.println("result1:"+result1+" result2:"+result2+" result3"+result3); } //乘法测试 @Test public void multipyTest(){ BigDecimalTest bigDecimalTest = new BigDecimalTest(); BigDecimal result1 = bigDecimalTest.multipy(999999999.0000,090900.09090099); BigDecimal result2 = bigDecimalTest.multipy("99989.99888777","76766666.99"); BigDecimal result3 = bigDecimalTest.multipy("989988.878",900000.00); BigDecimal result4 = bigDecimalTest.multipy("99988889",990900.90); BigDecimal result5 = bigDecimalTest.multipy("adb","888"); System.out.println("result1:"+result1+" result2:"+result2+" result3:"+result3 +" result4:"+result4+" result5:"+result5); System.out.println(new BigDecimal("123").abs()); } }
二、int和Integer的区别是什么?
1、类型差别
int是java的8个原始类型(int、short、char、float、double、Boolean、long、byte)之一,这几个原始类型不是对象;
Integer是对int的一个包装,是对象,符合java中万事万物皆对象的思想,包装了很多常用的操作。
2、存储的微众,大小
int是由jvm底层提供,有java虚拟机规范,int类型数据存储在局部变量去,占用一个数组单元;
Integer存储在java运行时数据区的堆中,不在使用时刻被垃圾回收机制回收。
Integer对象大小:
Mark Word:4个字节,标记位
Class对象指针:4字节,指向对应class对象的内存地址
对齐:对齐填充字节,按照8个字节填充
4+4+8=16字节
3、使用时,字节码的区别:
int类型字节码实例:
定义:int num1 = 32;
字节码:0:bipush 32
Integer类型字节码实例:
定义:Integer num2 = 64
字节码:
3:bipush 64
5:invokestatic #20 //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
联系:
相互转化:
Integer.valueOf(int)-->int 类型转为Integer类型
Integer.intValue() -->Integer类型转为int类型
当然也可以直接相互赋值:int num1 = 11;Integer num 2= num1;也是可以的
自动拆装箱操作(auto boxing/unboxing)
int --> Integer,装箱
Integer -->int,拆箱
注意:程序中尽量避免无意义的拆装箱操作,尤其是有性能考虑时(对象的创建回收)
Integer缓存机制源码分析:(Integer.valueOf())
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } //int转为Integer类型时,首先判断int值是否在缓存当中,如果在,就不会再去创建Integer对象; //缓存的数值范围(该段源码设置低位-128,高位127;): private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }
==说明:若为原始类型则比较值是否相等,若为对象,则比对地址是否相同;如下例子,Integer对象,值都相等,但是当值为128时,地址不相同,值为127值却相同
说明Integer缓存机制生效
@Test public void test2(){ Integer i1 = 128; Integer i2 = 128; System.out.println(i2 == i1);//结果:false Integer i3 = 127; Integer i4 = 127; System.out.println(i3 == i4);//结果:true }
-XX:AutoBoxCacheMax=256:通过将此JVM配置项添加到jvm中,可以调整如上代码总high的高位为256;
idea中选择工具栏中运行左边的下拉框,点击Edit Configurations,配置VM options 为:-ea -XX:AutoBoxCacheMax=256,保存
服务器上启动参数配置jvm参数
注意事项:在做相等判断时,若为元素类型则可以直接使用==,若为包装类型则需要使用equals
业务中若使用包装类型,要注意默认值是null的,这里最容易疏忽,因为元素类型默认值是0给大家养成了没有做null的不好习惯
扩展:
其它基本数据类型与对应的包装类型是否类型?是的
既然你看过源码,那么自动拆装箱时是否会使用到缓存机制呢?有,在生成字节码时,系统会自动调用Integer.valueOf()方法,用到这个方法,自然用到缓存机制
既然你看过源码,自动拆装箱时为啥可以做到自动转化?
语法糖
编译支持(字节码)
既然看过源码,也提到了Integer的缓存最大是127,但是我的系统中会有很多整数的使用,一般范围怎么调大
-XX:AutoBoxCacheMax=256
既然看过源码,说一下有哪些设计要点?
不可变性:
猜测:Integer内部装载的依旧是整数,而在相互转化时,可以基于intValue()获取int值,那就从
return value;
private final int value;
进而可知,Integer对象定义的对象也是不可变的
好处?保证了基本的信息安全和并发编程中的线程安全
移植性:
在64位操作系统写的代码移植到32位系统上,数据会否发生变化?
在Integer中定义了常量:
@Native public static final int SIZE = 32;
public static final int BYTES = SIZE/Byte.SIZE
java语言规范:无论是32位还是64位,开发者不需要担心位数的问题
有了Integer还要int干啥?或者有了int还要Integer干啥?
java号称纯面向对象,为啥搞一批原始类型让人去诟病,面向对象的一点不纯粹呢?
工程上的考虑,基本数据类型在执行效率和内存使用上提升软件性能,想想java刚出生的年代,硬件系统内存系统都没有现在那般牛逼,所以性能是工程师及其重视的问题。
其它?泛型的设计和考虑
查看生成的字节码:javap -vervose 类名 (注意,类名后面没有后缀)