(五) 面向对象 - 包装类与BigInteger、BigDecimal

对于基本数据类型,有时我们需要一个基本数据类型所对应的对象,而这个对象所对应的类我们称之为包装类。

 

由于像float、double浮点数表示,如果小数点后面数字太多,会出现精度缺失,但对于像银行等系统,精度缺失是灾难性的,而BigInteger、BigDecimal可以解决这个问题。

 
 

一、Number抽象类

 

public abstract class Number implements java.io.Serializable {

    public abstract int intValue();

   
    public abstract long longValue();


    public abstract float floatValue();


    public abstract double doubleValue();


    public byte byteValue() {
        return (byte)intValue();
    }


    public short shortValue() {
        return (short)intValue();
    }


    private static final long serialVersionUID = -8742448824652078965L;
}

 
 

一、介绍

 
Java.lang.Number类是数值包装类、BigInteger、BigDecimal的抽象父类。

他们有着共同的方法byteValue()、shortValue()、intValue()、longValue()、floatValue()、doubleValue()返回相应类型的值,这些共同方法在Number中定义,byteValue()、shortValue()方法实现是从intValue()来的。

 
 

二、最大、最小值查找

 
Number为数值包装类的父类,这样就可以定义方法来执行数值的共同操作,如果在Number类中没有doubleValue(),那么就无法从不同类型的数值中找到最大的数。

 

public class Find {

    public static void main(String[] args) {
        
        ArrayList<Number> list = new ArrayList<>();
        list.add(45);
        list.add(3445.53);
        list.add(new BigInteger("4355235252325646353"));
        list.add(new BigDecimal("2.352352352325235233"));
        list.add(Long.MAX_VALUE);
        System.out.println("最大值 = " + getLargestNumber(list));//最大值 = 9223372036854775807

        System.out.println("最小值 = " + getLeastNumber(list));//最小值 = 2.352352352325235233




    }
    public static Number getLargestNumber(ArrayList<Number> list) {
        if (list.size() == 0 || list == null)
            return 0;

        Number number  = list.get(0);
        for (int i = 1; i < list.size(); i++) {
            if (list.get(i).doubleValue() > number.doubleValue()) {
                number  = list.get(i);
            }
        }
        return number;
    }

    public static Number getLeastNumber(ArrayList<Number> list) {
        if (list.size() == 0 || list == null)
            return 0;

        Number number  = list.get(0);
        for (int i = 1; i < list.size(); i++) {
            if (list.get(i).doubleValue() < number.doubleValue()) {
                number  = list.get(i);
            }
        }
        return number;
    }



}

 
 

三、自定义数值包装类

 
分析:

有理数是一个含有分子分母,形式为a / b, b不为0。

同时值得注意的是应当将每个分子式是转换为最简形式。需要在该类中重写toString()方法,用于输出有理数。

由于Number类是数值包装类的根类,因此需要继承Number,另外有理数是可比较的,因此需要实现Comparable接口中的comparable方法。

 


public class Rational extends Number implements Comparable<Rational> {
  
  private long numerator = 0; //分子
  private long denominator = 1; //分母


  public Rational() {
    this(0, 1);
  }

  
  public Rational(long numerator, long denominator) {
    long gcd = gcd(numerator, denominator); //最大公约数
    this.numerator = ((denominator > 0) ? 1 : -1) * numerator / gcd;
    this.denominator = Math.abs(denominator) / gcd;
  }

  //两个数的最大公约数
  private long gcd(long n, long d) {
    long t1 = Math.abs(n);
    long t2 = Math.abs(d);
    long remainder = t1 % t2;

    while (remainder != 0) {
      t1 = t2;
      t2 = remainder;
      remainder = t1 % t2;
    }

    return t2;
  }

  
  public long getNumerator() {
    return numerator;
  }


  public long getDenominator() {
    return denominator;
  }

 //加
  public Rational add(Rational secondRational) {
    long n = numerator * secondRational.getDenominator() +
      denominator * secondRational.getNumerator();
    long d = denominator * secondRational.getDenominator();
    return new Rational(n, d);
  }

  //减
  public Rational subtract(Rational secondRational) {
    long n = numerator * secondRational.getDenominator()
      - denominator * secondRational.getNumerator();
    long d = denominator * secondRational.getDenominator();
    return new Rational(n, d);
  }

 //乘
  public Rational multiply(Rational secondRational) {
    long n = numerator * secondRational.getNumerator();
    long d = denominator * secondRational.getDenominator();
    return new Rational(n, d);
  }

  //除
  public Rational divide(Rational secondRational) {
    long n = numerator * secondRational.getDenominator();
    long d = denominator * secondRational.numerator;
    return new Rational(n, d);
  }

  @Override
  public String toString() {
    if (denominator == 1)
      return numerator + "";
    else
      return numerator + "/" + denominator;
  }

   @Override
  public boolean equals(Object parm1) {
      
   if(parm1 == this) return true;

    if(parm1 == null) return false;

    if(getClass() == parm1.getClass()){
      if ((this.subtract((Rational)(parm1))).getNumerator() == 0)
        return true;
    }

    return false;
  }

  @Override
  public int hashCode() {
    int hashCode = Long.hashCode(numerator);
    return hashCode = 31 * hashCode +Long.hashCode(denominator);
  }

   @Override
  public int intValue() {
    return (int)doubleValue();
  }

  @Override
  public float floatValue() {
    return (float)doubleValue();
  }

   @Override
  public double doubleValue() {
    return numerator * 1.0 / denominator;
  }

   @Override
  public long longValue() {
    return (long)doubleValue();
  }

  @Override
  public int compareTo(Rational o) {
    if ((this.subtract((Rational)o)).getNumerator() > 0)
      return 1;
    else if ((this.subtract((Rational)o)).getNumerator() < 0)
      return -1;
    else
      return 0;
  }
}

 
测试:

	@Test
    public void test1(){
        Rational rational1 = new Rational(1, 2);
        Rational rational2 = new Rational(2, -4);


        System.out.println(rational1);// 1/2
        System.out.println(rational2);// -1/2


        System.out.println(rational1.add(rational2));//0


    }

 
 

二、基本数据类型的包装类

 

一、对应关系

byte(Byte)、short(Short)、 int(Integer)、 long(Long)

double(Double)、 float(Float)

char(Character)、boolean(Boolean)

 
 

二、自动装箱、自动拆箱

 
自动装箱:

即基本数据类型转换为包装类,通过调用valueOf方法实现的。

Integer i = 1;

 
自动拆箱:

即包装类自动转换为基本数据类型,通过调用xxxValue方法实现的。

int i = Integer.valueOf(1);

 
 

三、类型转换

 
1、String与包装类转换:

//字符串 -> Integer对象
Integer integer = Integer.valueOf("123");
Integer.getInteger("123");
		
//字符串 -> int
int i = Integer.parseInt("123");
		
//int ->字符串
String s = String.valueOf(1);
String s1 = ""+1;
		
//Integer -> 字符串
String s2 = integer.toString();
String s3 = String.valueOf(integer);

 
 

2、基本数据类型 -> 包装类:

 
Int、long -> Integer、Long

@Test
public void test1(){
	Integer i1 = 100;//装箱
	Integer i2 = 100;
	Integer i3 = 200;
	Integer i4 = 200;
				
	System.out.println(i1==i2);//true
	System.out.println(i3==i4);//false
}
				 
结果分析:
	在发生装箱时会调用包装类的valueOf方法
	如果这个数在-128~127则会返回cache数组中值
	否则,会创建一个Integer对象返回

 
valueof方法:Long类似

private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer[] cache;
        static Integer[] archivedCache;

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    h = Math.max(parseInt(integerCacheHighPropValue), 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            // Load IntegerCache.archivedCache from archive, if possible
            VM.initializeFromArchive(IntegerCache.class);
            int size = (high - low) + 1;

            // Use the archived cache if it exists and is large enough
            if (archivedCache == null || size > archivedCache.length) {
                Integer[] c = new Integer[size];
                int j = low;
                for(int i = 0; i < c.length; i++) {
                    c[i] = new Integer(j++);
                }
                archivedCache = c;
            }
            cache = archivedCache;
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
}

  
@HotSpotIntrinsicCandidate
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
     return new Integer(i);
}

 
 
Float、double -> Float、Double:

@Test
public void test2(){
	Double i1 = 100.0;
	Double i2 = 100.0;
	Double i3 = 200.0;
	Double i4 = 200.0;
				
	System.out.println(i1==i2);//false
	System.out.println(i3==i4);//false
							
}
				 
结果分析:
	Float和Double的valueOf和Integer不同,它们会直接返回一个new的对象

 
valueOf方法:

@HotSpotIntrinsicCandidate
public static Double valueOf(double d) {
        return new Double(d);
}

 
 
boolean -> Boolean:

@Test
public void test3(){
	Boolean i1 = false;
	Boolean i2 = false;
	Boolean i3 = true;
	Boolean i4 = true;
				
	System.out.println(i1==i2);//true
	System.out.println(i3==i4);//true
}
				 
结果分析:
	查看源码发现其valueOf方法内是一个三元表达式,
	有两个常量对象:FALSE和TRUE

 
valueOf():


public static final Boolean TRUE = new Boolean(true);

public static final Boolean FALSE = new Boolean(false);

....
    
@HotSpotIntrinsicCandidate
public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
}

 
 
3、包装类 -> 基本数据类型

 
调用xxxValue,比如Integer -> int ,则调用intValue方法

@Test
public void test4(){
	Integer a = 1;
	Integer b = 2;
	Integer c = 3;
	Integer d = 3;
	Integer e = 321;
	Integer f = 321;
	Long g = 3L;
	Long h = 2L;
				
	System.out.println(c==d);//true
	System.out.println(e==f);//false
	System.out.println(c==(a+b));//true
	System.out.println(c.equals(a+b));//true
	System.out.println(g==(a+b));//true
	System.out.println(g.equals(a+b));//false
	System.out.println(g.equals(a+h));//true
				
}
				 
结果分析:
	注意在"=="的两个操作符,如果其中一个是表达式,则比较的是数值(拆箱)
	另外,equals并不会进行类型转换.

 
 

三、BigInteger、BigDecimal类

BigInteger:表示不可变的任意大小的整数。

BigDecimal:表示不可变的,支持任意精度的小数。

 

@Test
public void test1(){
	BigDecimal bigDecimal = new BigDecimal("121.313231287321");
	BigDecimal bigDecimal1 = new BigDecimal("21.414124");
	BigDecimal divide = bigDecimal.divide(bigDecimal1,12,RoundingMode.HALF_UP );
    
	System.out.println(divide);//5.665103615134
}

 
 
参考资料:
《Java语言程序设计》、博客、尚硅谷资料等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值