基本数据类型

1 基本数据类型与其封装器类

Java中的基本数据类型包括了char、boolean、byte、short、int、long、float、double、void。

基本数据类型 封装器类 位数 范围
char Character 16 存储unicode码,用单引号赋值,ch='\u0000'
boolean Boolean / true或false
byte Byte 8位 -128~127
short Short 16位 -32768~32767
int Integer 32位 -232~232-1
long Long 64位 -264~264-1
float Float 32位 3.4e-45~1.4e38,赋值需要在尾部加上f或F
double Double 64位 4.9e-324~1.8e308
void Void / /

2 Boolean

Boolean是boolean的封装器类,在Boolean类中使用了private final boolean value;来存储值,该类还提供了toString、toBoolean等方法。

3 Byte、Short、Int、Long、Float、Double

这几个封装器类中提供了MIN_VALUE和MAX_VALUE来存储该类的上下限。
在这些类中提供了parseT(String s)decodeT(String s)来将字符串转换为对应类型。这两种方接收变量可以是16进制(0X、0x、#)或8进制(0)或十进制的数。其中parseT在对非10进制的数进行解析时,需要加上进制的参数,即parseT(String s, int radix),而decodeT不需要,可以直接对0x、0X等标志进行处理。
这些类还提供了byteValue()shortValue()intValue()longValue()floatValue()doubleValue()来得到该值的其他类型的对象引用。

4 对象池

Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1==i2);
//output:true

Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3==i4);
//output:false

在上述的代码中i1==i2的原因是在Byte、Short、Int、Long这四个封装器类中包含了一个TCache[256],初始化了从-128~127这256个数的对象。当用户创建该范围内的封装器类时,直接从TCache中已创建并初始化了的对象。而当i3、i4创建值为128的封装器对象时,由于cache中不存在,因此会申请内存空间并创建,所以此时i3!=i4

Boolean b1=new Boolean(false);
Boolean b2=b1;
b2=true;
System.out.println("b1="+b1+",b2="+b2);
//output:b1=false,b2=true

在该段代码中,b1与b2均为对象引用,但是对b2修改并未对b1产生影响,因此可以把false和true也当作两个已在cache中初始化的对象。
对象池的存在使得内存得以节省,并且加快了对象池中对象的对比。(==比equals()快,对于对象池中对象的比较,可以直接使用==)

学习源码

/*
 * 从一个数中获得二进制中最高一位是多少
 * highestOneBit(1) =1,highestOneBit(2)=2,highestOneBit(3)=2
 */
public static int highestOneBit(int i) {
        // HD, Figure 3-1
        i |= (i >>  1);
        i |= (i >>  2);
        i |= (i >>  4);
        i |= (i >>  8);
        i |= (i >> 16);
        return i - (i >>> 1);
}
/*
 * 从一个数中获得二进制中最低一位是多少
 * lowestOneBit(1) =1,lowestOneBit(2)=2,lowestOneBit(3)=1
 */
public static int lowestOneBit(int i) {
        // HD, Section 2-1
        return i & -i;
}
/*
 * 从一个数中获得二进制中前面有多少个连续的0
 */
public static int numberOfLeadingZeros(int i) {
        // HD, Figure 5-6
        if (i == 0)
            return 32;
        int n = 1;
        if (i >>> 16 == 0) { n += 16; i <<= 16; }
        if (i >>> 24 == 0) { n +=  8; i <<=  8; }
        if (i >>> 28 == 0) { n +=  4; i <<=  4; }
        if (i >>> 30 == 0) { n +=  2; i <<=  2; }
        n -= i >>> 31;
        return n;
}
/*
 * 从一个数中获得二进制中后面有多少个连续的0
 */
public static int numberOfTrailingZeros(int i) {
        // HD, Figure 5-14
        int y;
        if (i == 0) return 32;
        int n = 31;
        y = i <<16; if (y != 0) { n = n -16; i = y; }
        y = i << 8; if (y != 0) { n = n - 8; i = y; }
        y = i << 4; if (y != 0) { n = n - 4; i = y; }
        y = i << 2; if (y != 0) { n = n - 2; i = y; }
        return n - ((i << 1) >>> 31);
}

这两个方法所用的技巧都是一样的,通过对二进制码进行位移操作,判断首部或者尾部是否为0或不为0来判断位数。首先对32位中的某16位进行判断,如果条件成立,则判断另16位;如果条件不成立,则继续判断该16位中的某8位。

/*
 * 判断一个数的二进制形式有多少个1
 */
public static int bitCount(int i) {
        // HD, Figure 5-2
        i = i - ((i >>> 1) & 0x55555555);
        i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
        i = (i + (i >>> 4)) & 0x0f0f0f0f;
        i = i + (i >>> 8);
        i = i + (i >>> 16);
        return i & 0x3f;
}

该方法使用了分治法,先计算每2位有多少个1,再计算每4位有多少个1,然后计算8位、16位和32位,最后得到结果。
第一行i = i - ((i >>> 1) & 0x55555555);计算了每2位有多少个1,即第0、1位,第2、3位···,证明可用枚举的方法(怀疑是某种方法的变换形式,否则光靠想就能想出这代码,着实有点厉害)。剩下的代码使用了相似的方法来合并1的个数,其中i = (i + (i >>> 4)) & 0x0f0f0f0f;与上一行不同的原因是此时合并2个4位的1的个数,此时4位最大能表示15,用这种计算方法能省下一次与运算。最后通过i & 0x3f将高位全置0。

public static long rotateLeft(long i, int distance) {
        return (i << distance) | (i >>> -distance);
}

其中i>>>-distance等价于i>>>sizeof(Long)-distance

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容