java是强类型语言,它提供了八种基本数据类型, 其中有六种数字类型,分别是byte、short、int、long、float、double。本博文主要介绍的Number类。
一、Number类的定义1.包装类:java是一个面向对象的语言,但java的基本数据类型却不是面向对象的,这在实际的使用中会有诸多不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表。这八个和基本类型对应的类统称为包装类。 2.包装类的主要用途:同基本数据类型对应的类类型存在,方便涉及到对象的操作、每个类中包含每种基本数据类型相关属性如最大值、最小值等,以及相关的操作方法。 3.抽象类:用来表征对问题领域进行分析、设计中得出的抽象概念,使用abstract 修饰类名。抽象类不能创建对象。 4.抽象方法:只有方法声明,而没有具体方法体的方法。只能定义在抽象类中。用abstract修饰方法名。 5.接口:java语言中存在的有特定的语法和结构。用interface修饰接口名,接口中的方法都是抽象方法(jdk1.7以前,1.8及以后可以有默认方法) 接口中的变量都是常量。
public interface Serializable {
}
Serializable是一个接口,可以看到该接口中什么都没有,它是一个标识,实现了Serializable接口的类可以被序列化(可查看文章末尾序列化的定义)
serialVersionUID:
这个是用于对类进行版本控制的,对象反序列化(可查看文章末尾反序列化的定义)的时候会用到。
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();
}
可以看到这些方法都是xxxValue,目的就是将数据转换为相对应的类型,如intValue就是将数据转换为int类型,byteValue就是将数据转换为byte类型,这点从返回值我们也可以看出来
1.byte、short、int、long、float、double都是数字类型,java为什么要搞出这么多的数字类型出来。 答1:因为它们的长度各不相同,使用它们是系统开销也不相同。它们有不同的特点,适用于不同的地方。我们可以根据不同的需要,而选择类型。
2.Number是这些类型的父类,既然他们的范围不一样,那么转换时会不会出问题 答2:转换时当然会出问题,比如int类型的129你将它转换为byte时就会越界,得到的结果是-127。其它的大类型转换为小类型的时候也会有同样的问题,所以使用的时候要格外小心。
序列化:把对象转换为字节序列的过程称为对象的序列化。转换后的字节序列通常存储于文件或数据库,用于网络传输等。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
byte即字节的意思,java中的基本类型之一、也是java中长度最小的基本数字类型,通常在读取文件时需要用字节数组来保存文件内容。byte数组也常被用作缓冲器,接收文件内容。不管是读还是写文件都会用到。接下来就让我们看看byte类型的包装类Byte类的实现。
public final class Byte extends Number implements Comparable {
...
}
可以看到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
public static final Class TYPE = (Class) Class.getPrimitiveClass("byte");
其中Class.getPrimitiveClass的源码为:
static native Class getPrimitiveClass(String name);
这个TYPE表示的是基本类型 byte 的 Class 实例,即byte.class
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类的源码时再讲解。
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的,避免重复的实例化和回收。
public static Byte valueOf(byte b) {
final int offset = 128;
return ByteCache.cache[(int)b + offset];
}
这里的valueOf其实就是从上述缓存数组中取得对应的byte对象。因为数组下标是从0开始的不包含负数,所以这里会加上一个offset来取得数组对应位置的元素值
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进制。
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));
}
public static Byte valueOf(String s) throws NumberFormatException {
return valueOf(s, 10);
}
public boolean equals(Object obj) {
if (obj instanceof Byte) {
return value == ((Byte)obj).byteValue();
}
return false;
}
比较两个Byte对象是否是同一个对象,分为两步:第一步判断传入的对象是否是Byte类型,java中用instanceof判断对象是否是某个类型的对象。第二步判断两个对应的value值是否相等。如果这两个条件都满足那么这两个对象就是同一个对象。
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表示第一个数据小于第二个数据
注意:
在本类中有很多使用static和final关键字修饰的属性或方法。用static 和final共同修饰的变量表示这个量为常量,不可改变。用static修饰的方法或属性表示该属性属于类,可以使用 类名.方法名或类名.属性名直接调用。否则这些属性属于对象,需要通过创建对象后,由对象来调用。
博文参考