我们已经知道,Java的数据类型分两种:
byte
,short
,int
,long
,boolean
,float
,double
,char
class
和interface
类型引用类型可以赋值为null
,表示空,但基本类型不能赋值为null
:
如何把一个基本类型视为对象(引用类型)?
比如,想要把int
基本类型变成一个引用类型,我们可以定义一个Integer
类,它只包含一个实例字段int
,这样,Integer
类就可以视为int
的包装类(Wrapper Class):
public class Integer { private int value; public Integer(int value) { this.value = value; } public int intValue() { return this.value; } }
定义好了Integer
类,我们就可以把int
和Integer
互相转换:
Integer n = null; Integer n2 = new Integer(99); int n3 = n2.intValue();
实际上,因为包装类型非常有用,Java核心库为每种基本类型都提供了对应的包装类型:
基本类型 | 对应的引用类型 |
---|---|
boolean | java.lang.Boolean |
byte | java.lang.Byte |
short | java.lang.Short |
int | java.lang.Integer |
long | java.lang.Long |
float | java.lang.Float |
double | java.lang.Double |
char | java.lang.Character |
Integer n = 100; // 编译器自动使用Integer.valueOf(int) int x = n; // 编译器自动使用Integer.intValue()
装箱和拆箱会影响代码的执行效率,因为编译后的class
代码是严格区分基本类型和引用类型的。
所有的包装类型都是不变类。我们查看Integer
的源码可知,它的核心代码如下:
对两个Integer
实例进行比较要特别注意:绝对不能用==
比较,因为Integer
是引用类型,必须使用equals()
比较:
因为Integer.valueOf()
可能始终返回同一个Integer
实例,因此,在我们自己创建Integer
的时候,以下两种方法:
Integer n = new Integer(100);
Integer n = Integer.valueOf(100);
方法2更好,因为方法1总是创建新的Integer
实例,方法2把内部优化留给Integer
的实现者去做,即使在当前版本没有优化,也有可能在下一个版本进行优化。
我们把能创建“新”对象的静态方法称为静态工厂方法。Integer.valueOf()
就是静态工厂方法,它尽可能地返回缓存的实例以节省内存。
创建新对象时,优先选用静态工厂方法而不是new操作符。
public class Main { public static void main(String[] args) { System.out.println(Integer.toString(100)); // "100",表示为10进制 System.out.println(Integer.toString(100, 36)); // "2s",表示为36进制 System.out.println(Integer.toHexString(100)); // "64",表示为16进制 System.out.println(Integer.toOctalString(100)); // "144",表示为8进制 System.out.println(Integer.toBinaryString(100)); // "1100100",表示为2进制 } }
// boolean只有两个值true/false,其包装类型只需要引用Boolean提供的静态字段: Boolean t = Boolean.TRUE; Boolean f = Boolean.FALSE; // int可表示的最大/最小值: int max = Integer.MAX_VALUE; // 2147483647 int min = Integer.MIN_VALUE; // -2147483648 // long类型占用的bit和byte数量: int sizeOfLong = Long.SIZE; // 64 (bits) int bytesOfLong = Long.BYTES; // 8 (bytes)
最后,所有的整数和浮点数的包装类型都继承自Number
,因此,可以非常方便地直接通过包装类型获取各种基本类型:
// 向上转型为Number: Number num = new Integer(999); // 获取byte, int, long, float, double: byte b = num.byteValue(); int n = num.intValue(); long ln = num.longValue(); float f = num.floatValue(); double d = num.doubleValue();
在Java中,并没有无符号整型(Unsigned)的基本数据类型。byte
、short
、int
和long
都是带符号整型,最高位是符号位
例如,byte是有符号整型,范围是-128
`+127`,但如果把`byte`看作无符号整型,它的范围就是`0`255
。我们把一个负的byte
按无符号整型转换为int
:
public class Main { public static void main(String[] args) { byte x = -1; byte y = 127; System.out.println(Byte.toUnsignedInt(x)); // 255 System.out.println(Byte.toUnsignedInt(y)); // 127 } }