一起学JDK源码 -- Byte类

byte即字节的意思,java中的基本类型之一、也是java中长度最小的基本数字类型,通常在读取文件时需要用字节数组来保存文件内容。byte数组也常被用作缓冲器,接收文件内容。不管是读还是写文件都会用到。接下来就让我们看看byte类型的包装类Byte类的实现。

基础知识:

1.java的基本数据类型byte、short、int、long、float、double、char所占的字节长度分别为1、2、4、8、4、8、2。至于boolean所占的长度众说纷纭,有人说boolean只有真和假,只用一位存储就够了。实际上存储空间的基本计量单位是字节,不是位。所以boolean至少占一个字节。JVM规范中,boolean变量作为int处理,也就是4字节;boolean数组当做byte数组处理。
2.java中字节容量的关系:
1TB=1024GB TB是千千兆
1GB=1024MB GB是千兆
1MB=1024KB MB是兆
1KB=1024Byte KB是千字节
1Byte = 8bit 一个字节是8位
3.byte与bit的关系:
我们上面所说的字节也就是byte,是计算机文件大小的基本单位,而bit是Binary digit(二进制数位)的缩写,意为“位”或“比特”,是计算机运算的基础,计算机存储数据都是0和1组成的,每个0或1也就是占这里的1位,即一个bit.
4.源码、反码、补码:
在计算机内,定点数有3种表示法:原码、反码和补码
原码:就是二进制定点表示法,即最高位为符号位,“0”表示正,“1”表示负,其余位表示数值的大小。
反码:表示法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
补码:表示法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。
JAVA中用补码表示二进制数.
5.位运算
java中的位运算包括"或"(|)、"与"(&)、"非"(~)、"异或"(^)
| : 两个操作数的位中,有一个为1,结果才为1,否则结果为0
& :两个操作数的位中,全为1,结果才为1,否则结果为0
~ : 如果位为0,结果是1,如果位为1,结果是0
^ : 两个操作数的位中,相同则结果为0,不同则结果为1
上述操作数的位表示的是把目标数据转换为二进制后的每一位,举个栗子:7 & 10
7转换为二进制后: 0 1 1 1
&
10转换为二进制后: 1 0 1 0
上下按&的规则计算结果为 0 0 1 0
即7&10 = 2 ,其它的位运算操作类似

Byte类:

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

可以看到Byte类继承了Number类,而又不是抽象类,自然要重写Number类中的xxxValue方法。另外Byte类实现了Comparable接口,Comparable是一个接口,该接口定义类的自然顺序,实现该接口的类就可以按这种方式排序,一般情况下如果某类对象自身具有比较的特性就可以实现该接口,比如这里的Byte代表的是一种数,而数本身就具有比较的特性,就可以实现该接口。

边界值:

public static final byte   MIN_VALUE = -128;
public static final byte   MAX_VALUE = 127;

诶,为什么最大值是127,最小值是-128.在基础知识中介绍了,java中用补码表示二进制。byte为1个字节,即8位。最高位是符号位。最大值是01111111,因正数的补码是其本身,即最大值的补码是01111111,最大值的原码也是01111111,所以,此正数为01111111即用十进制表示形式为127。最小值是10000000,由于是补码需要转换成原码,因此先减去1即01111111,然后取反10000000,这就是原码,原码就是10000000,这就是最小值的绝对值,即2^7=128,那么,最小值就是-128

TYPE:

public static final Class<Byte>     TYPE = (Class<Byte>) Class.getPrimitiveClass("byte");
其中Class.getPrimitiveClass的源码为:
static native Class<?> getPrimitiveClass(String name);

这个TYPE表示的是基本类型 byte 的 Class 实例,即byte.class

toString(byte b):

public static String toString(byte b) {
    return Integer.toString((int)b, 10);
}

注意这里的toString可不是重写的Object类中的toString方法,Object中的toString方法是没有参数的,方法重写必须和父类中的方法一模一样。这里是将byte数据转换为对应的字符串形式,它调用了Integer.toString(int i, int radix)方法,这个方法等我们看Integer类的源码时再讲解。

ByteCache:

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类型的数组,数组的长度刚好是Byte类中最小值到最大值之间的长度(负数128个,正数127个加上0共256个)。在静态代码块中创建了这256个对象放到cache数组中,之前也介绍了静态代码块在类一加载的时候就会执行。这里是将byte类型所有的可能值(对于byte来说其实它的可能值就是从-128到127,一共256个)缓存起来,只能创建256个Byte对象就可以表示所有可能的byte。而且这些都是静态且final的,避免重复的实例化和回收。

valueOf(byte b):

public static Byte valueOf(byte b) {
        final int offset = 128;
        return ByteCache.cache[(int)b + offset];
}

这里的valueOf其实就是从上述缓存数组中取得对应的byte对象。因为数组下标是从0开始的不包含负数,所以这里会加上一个offset来取得数组对应位置的元素值

parseByte(String s, int radix):

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

这个方法从方法名也可以看出来其作用,就是将一个字符串为byte,首先它调用了 Integer.parseInt(s, radix)将目标字符串转换为int值(对于这个方法我们看Integer类的源码时再讲),然后判断转换后的值是否在byte类型的数值范围内,如果是就返回,否就抛出一个异常。其中s就是要转换的目标字符串,radix就是目标字符串的进制表示法,常用的有2进制、8进制、10进制和16进制。

parseByte(String s):

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

将10进制表示的字符串转换为byte数字。这个方法实际上是调用了上面的方法parseByte(String s, int radix),只不过固定的转换的进制为10进制。

valueOf(String s, int radix)和 valueOf(String s) :

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

获取指定进制字符串,转换为byte后对应的Byte对象。在上面我们看了valueOf(byte b),获取byte数对应的Byte对应,这里无非是将传入的参数换成了字符串,在内部先将字符串转换为byte数然后再从缓存数组中获取对应的Byte对象。将字符串转换为byte数字和从缓存数组中取Byte对象在上面已经讲过了,这里就不再赘述了。

decode(String nm):

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

将其它进制表示法,表示的字符串数据转换为10进制表示的byte数据,然后返回对应的Byte对象。其中常用的"其它"进制表示法有16进制表示法(数字前加0x或#)、8进制表示法(在数字前面加0)、2进制表示法(用0和1表示数字)。具体怎么转换的要看Integer.decode(nm)的源码(对于这个方法我们看Integer类的源码时再讲)。最后判断下转换后的数据是否在byte类型的数值范围内,然后调用valueOf(byte b)方法从缓存中获取Byte对象.

数据存放位置:

private final byte value;

既然Byte为byte类型的包装类,每个byte对应一个Byte对象那byte对应的值存放在什么位置呢,就存在于这里的value属性中。

构造器:

public Byte(byte value) {
        this.value = value;
}
public Byte(String s) throws NumberFormatException {
        this.value = parseByte(s, 10);
}

java中的构造器是用于创建对象和初始化对象中的属性用的。Byte类中提供了两个构造器,一个是通过传byte数据来构造对象,一个是通过传字符串数据来创建对象,可以看到最终都是将传入的数据赋值给了value,也就是上面讲的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;
}

这里的xxxValue也就是重写了父类Number类中的xxxValue方法,可以看到这些方法用的都是java的强制类型转换机制,由于这些转换中byte的长度最小,所以不用考虑数据溢出的问题。

hashCode:

@Override
public int hashCode() {
    return Byte.hashCode(value);
}
public static int hashCode(byte value) {
    return (int)value;
}

这里是重写Object的hashCode方法,可以看到返回的就是Byte对象表示的数值。至于hashCode方法是什么意思在看Object类的源码时已经讲到了,如果忘记了可以再回去看一下。

equals:

public boolean equals(Object obj) {
        if (obj instanceof Byte) {
            return value == ((Byte)obj).byteValue();
        }
        return false;
}

比较两个Byte对象是否是同一个对象,分为两步:第一步判断传入的对象是否是Byte类型,java中用instanceof判断对象是否是某个类型的对象。第二步判断两个对应的value值是否相等。如果这两个条件都满足那么这两个对象就是同一个对象。

compareTo

public int compareTo(Byte anotherByte) {
    return compare(this.value, anotherByte.value);
}

这个方法是实现了Comparable接口中的抽象方法,该方法的作用在文章开始的时候已经讲解了。可以看到在方法内部调用了compare方法,这个方法的源码如下:

public static int compare(byte x, byte y) {
        return x - y;
}

可以看到返回的是两个byte数据的差值,需要注意的一点是在compareTo的比较机制中如果返回值大于0表示前一个数据比后一个数据大,返回值等于 0表示两个数据相等,返回值小于0表示第一个数据小于第二个数据

toUnsignedInt(byte x)

public static int toUnsignedInt(byte x) {
        return ((int) x) & 0xff;
}

这个方法是jdk1.8之后新加的,作用是将byte数据转换为无符号的int数据。方法的实现很简单就是将目标值和0xff这个数做&的运算。&运算如果有不清楚的可以看下本章的基础知识。

toUnsignedLong

public static long toUnsignedLong(byte x) {
        return ((long) x) & 0xffL;
}

这个方法同toUnsignedInt类似只不过把数据强转为long类型后进行运算。注意同一个byte类型的数据转换成int和long后所表示的二进制的数据的位数是不相同的int为32位,long是64位。

SIZE:

public static final int SIZE = 8;

SIZE用来表示于二进制补码形式的byte值的位数,值为8,静态变量且不可变。

BYTES:

public static final int BYTES = SIZE / Byte.SIZE;

BYTES用来表示于二进制补码形式的byte值的字节数,值为1,静态变量且不可变。

注意:
在本类中有很多使用static和final关键字修饰的属性或方法。用static 和final共同修饰的变量表示这个量为常量,不可改变。用static修饰的方法或属性表示该属性属于类,可以使用 类名.方法名或类名.属性名直接调用。否则这些属性属于对象,需要通过创建对象后,由对象来调用。

查看所有目录

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,738评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,377评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,774评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,032评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,015评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,239评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,724评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,374评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,410评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,457评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,132评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,733评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,804评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,022评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,515评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,116评论 2 341

推荐阅读更多精彩内容