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。