Java 7源码分析第2篇 - Java数值类型

本文详细解析了 Java 中 Number 类型及其子类 Byte 的源代码,介绍了数值类型之间的转换方式及 Byte 类型的缓存机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在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进行更小范围内的转换。

查看Byte.java源代码,如下:

 // --------------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.java类中剩下的源代码吧。

public final class Byte extends Number implements Comparable<Byte> {

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

    public static final Class<Byte>     TYPE = (Class<Byte>) Class.getPrimitiveClass("byte");

    public static String toString(byte b) {
        return Integer.toString((int)b, 10);
    }
    // 静态内部类 
    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];
    }

   // 由于int所能表示的范围包含了byte,所以完全可以按int型进行处理
    public static byte parseByte(String s, int radix)
        throws NumberFormatException {
        int i = Integer.parseInt(s, radix);
        if (i < MIN_VALUE || i > MAX_VALUE)
            throw new NumberFormatException(                                                                                                                                  "Value out of range. Value:\"" + s + "\" Radix:" + radix);
        return (byte)i;
    }

    public static byte parseByte(String s) throws NumberFormatException {
        return parseByte(s, 10);
    }

    public static Byte valueOf(String s, int radix)
        throws NumberFormatException {
        return valueOf(parseByte(s, radix));//等同于new Byte(Byte.parseByte(s, radix))
    }

    public static Byte valueOf(String s) throws NumberFormatException {
        return valueOf(s, 10);
    }

    public static Byte decode(String nm) throws NumberFormatException {
        int i = Integer.decode(nm);
        if (i < MIN_VALUE || i > MAX_VALUE) throw new NumberFormatException("Value " + i + " out of range from input " + nm);
        return valueOf((byte)i);
    }
   
    
    
    public String toString() {
        return Integer.toString((int)value);
    }

    public int hashCode() {
        return (int)value;
    }

    public boolean equals(Object obj) {
        if (obj instanceof Byte) {
            return value == ((Byte)obj).byteValue();
        }
        return false;
    }
    // 对两个Byte类型的数进行比较
    public int compareTo(Byte anotherByte) {
        return compare(this.value, anotherByte.value);
    }
    public static int compare(byte x, byte y) {
        return x - y;
    }

    // 一个byte类型用8位表示,也就是一个字节 
    public static final int SIZE = 8;
   
    public Byte(String s) throws NumberFormatException {
        this.value = parseByte(s, 10);
    }
    // ...
    private static final long serialVersionUID = -7183698231559129828L;
}
从源代码中应该看出以下几点:

(1)由于Integer所能表示的数值类型比Byte要大,所以可直接将Byte类型转换为Integer类型,然后调用Integer类型对应的方法进行,如如上的方法中调用Integer.decode(nm)、Integer.toString()和Integer.parseInt(s, radix)来处理。

(2)类中valueof(byte b)方法和ByteCache()方法实现了数据的缓存功能。使用了私有的静态内部类来缓存Byte类型的所有数值,也就是-128~127。

Byte a=-122;
Byte b=-122;
System.out.println(a==b);// 值为true

可以看到,两个包装类型是相同的,这主要就是缓存的原因,同时也是享元设计模式的一种具体实现。
而如上使用静态内部类已经更好的延迟了缓存。可以想像一下,如果使用静态块来执行如上的代码,那么当类在第一次使用时代码就会得到执行,但是这是不必要的。因为程序员可能只是调用Byte类的其他功能方法,如toString()方法。如果代码执行了,就会缓存,浪费内存。但是使用静态内部类时,只有当定义了一个Byte类型时,代码才会得到执行。如:
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);//true
System.out.println(e == f); // false
结果可想而知。

PS:以后将深入讲解:
(1)hashCode()和equals()方法
(2)继承Comparable接口实现类的比较




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值