Java 7之基础类型第2篇 - Java整数类型(1)

时间:2021-08-24 17:28:01
转载请注明出处:

1、Number类


在Java中,能够表示数值的数据类型有6种,主要分为两类,一类是可以表示小数的float和double类型,另外一类就是只能表示整数类型的byte、short、int和long类型了。这些基本类型对应的封装类型都继承了Number类,Number.java类的源代码如下:

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;}

         可以看到,其实对于每个Number抽象类的实现类都实现了如上4个抽象方法,也就是说可以调用xxxValue()方法进行任意数值类型的转换。但是需要注意的是转换过程中各个类型所能表示的精度和范围。

在如上的抽象类中实现了由int类型转换到byte和short类型的方法,也就是执行类型的强制转换但是没有对其它的转换类型进行实现,如提供将long类型转换为short、byte类型。可能Java设计师们是考虑到一种普通大众的情况吧,经常有人直接使用强制类型对int进行更小范围内的转换。

2、Byte类

几乎所有继承Number类的类都对如上定义的几个方法进行了重新的实现,如Byte类:

 // --------------byte与其他几种数值类型进行转换--------------------------    public byte byteValue() {        return value;    }    public short shortValue() {        return (short)value;    }    public int intValue() {        return (int)value;    }    public long longValue() {        return (long)value;    }    public float floatValue() {        return (float)value;    }    public double doubleValue() {        return (double)value;    }
也是在执行类型的强制转换。所以说通过调用用方法得到的结果与我们强制类型转换后的结果一致,只是以面向对象的方法提供出来更加符合了Java的设计思想而已。

下面来继续看一下Byte类中定义的几个重要的属性吧及构造方法吧。

public final class Byte extends Number implements Comparable<Byte> {    // 一个byte类型用8位表示,也就是一个字节     public static final int SIZE = 8;    public static final byte MIN_VALUE = -128;// -2^8     public static final byte MAX_VALUE = 127;// 2^7-1     private final  byte value;     // 构造函数     public Byte(byte value) { this.value = value; } // 将字符串转换为byte值,可能会转换失败而抛出异常    public Byte(String s) throws NumberFormatException {        this.value = parseByte(s, 10);    }}

如上定义了一个Byte类型所有表示的最大和最小整数值,同时还定义了一个byte类型的value,这些属性由final修饰,不可改变。final类型的数据(基本类型和引用类型)分为编译时确定值和运行时确定值两类。都要保证在使用前进行初始化。若在定义时没有显示初始化,是没有默认初值的。对于在定义时没有显式初始化的,应该在构造方法中进行初始化,这时可以利用不同参数传递给它,使得它可以根据具体对象的不同而不同,并且保证在不同的对象中始终唯一。所以不要试图改变value值,如下代码是错误的:
Float y=9.99f;y=22;// 值不可改变	
byte数值还有可能进行缓存,以提高效率,如下:
    // 静态内部类,对一些Byte类型的数值进行缓存    private static class ByteCache {        private ByteCache(){}        static final Byte cache[] = new Byte[-(-128) + 127 + 1];        static {            for(int i = 0; i < cache.length; i++)                cache[i] = new Byte((byte)(i - 128));        }    }    // 将原始类型的byte转换为包装类型的Byte    public static Byte valueOf(byte b) {        final int offset = 128;        return ByteCache.cache[(int)b + offset];    }

一个静态私有的内部类中定义了一个非常重要的Byte数组cache[]。这个cache在什么时候进行初始化呢?是在ByteCache静态类加载的时候,通过运行static静态块来完成的。那么这个静态内部类到底在什么时候加载呢?肯定是在valueOf()方法中调用的时候。

试想一下,如果在Byte类加载的时候就对这256个Byte数进行缓存,那么有可能会造成资源的浪费。因为程序可能根本用到不。所以如上的写法已经把缓存数组延迟到最迟加载了,也就是第一次在使用Byte数值的时候,默认都会调用valueOf() 方法,如下:

public class test06 {	public static void main(String args[]) {		Byte a=8;    }}
编译运行这个类后,查看二进制文件test06.class,如下:
// Compiled from test06.java (version 1.7 : 51.0, super bit)public class test.test06 {    // Method descriptor #6 ()V  // Stack: 1, Locals: 1  public test06();    0  aload_0 [this]    1  invokespecial java.lang.Object() [8]    4  return      Line numbers:        [pc: 0, line: 3]      Local variable table:        [pc: 0, pc: 5] local: this index: 0 type: test.test06    // Method descriptor #15 ([Ljava/lang/String;)V  // Stack: 1, Locals: 2  public static void main(java.lang.String[] args);    0  bipush 8    2  invokestatic java.lang.Byte.valueOf(byte) : java.lang.Byte [16]    5  astore_1 [a]    6  return      Line numbers:        [pc: 0, line: 5]        [pc: 6, line: 6]      Local variable table:        [pc: 0, pc: 7] local: args index: 0 type: java.lang.String[]        [pc: 6, pc: 7] local: a index: 1 type: java.lang.Byte}
在main方法中的偏移量为2一行中发现,Java转为调用了valueOf(byte)方法来查找这个值,这就实现了Byte值的共享。

其实,数值类型中除了Float和Double类型外,Byte,Short,Integer,Long,Character,Boolean都实现了这种数值的共享,并且也都是-127~128区间值的缓存,而对于不在这个区间范围内的值,只能new一个对应的包装类型进行返回了。举个例子:

Integer c = 3;Integer d = 3;Integer e = 321;Integer f = 321;
运行结果如下:
System.out.println(c == d); // trueSystem.out.println(e == f); // false

Byte中hashCode()和equals()方法的实现如下:

 public int hashCode() {        return (int)value;    }    public boolean equals(Object obj) {        if (obj instanceof Byte) {            return value == ((Byte)obj).byteValue();        }        return false;    }
hashCode()值为byte值本身。当调用equals()方法进行Byte值的比较时,和调用==进行比较的效果是一样的。

由于4个整数类型和Float、Double类型都继承了Comparable接口,并且也都实现了compareTo()方法,所以可以比较他们的大小,并且在必要的时候进行排序。如果对这个知识点不清楚,可以参阅如下一篇文章:

http://blog.csdn.net/mazhimazh/article/details/16844327

剩下的其他一些方法非常简单,有兴趣的读者可以自己去阅读。