对于基本数据类型,有时我们需要一个基本数据类型所对应的对象,而这个对象所对应的类我们称之为包装类。
由于像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语言程序设计》、博客、尚硅谷资料等