java中类型可以分为2大类: 基本类型和引用类型
基本类型包括:
类型名称 | 描述信息 |
---|---|
boolean | true或者false,与JVM实现相关,我自己的JVM中是使用了1个byte。 可以用这个来测试:https://blog.csdn.net/jeffhtlee/article/details/7839377 |
char | 16位,因为使用unicode编码。 用单引号括起来的单个字符。 |
byte | 8位整数,带符号 |
short | 16位整数,带符号 |
int | 32位整数,带符号 |
long | 64位整数,带符号 |
float | 32位浮点数 |
double | 64位浮点数 |
除了基本类型,其他都为引用类型,包括我们常用的String类等等。
实际上每个基本类型,都有一个包装器类型与之相对应,这些包装器类型都是引用类型:
int(4字节) | Integer |
byte(1字节) | Byte |
short(2字节) | Short |
long(8字节) | Long |
float(4字节) | Float |
double(8字节) | Double |
char(2字节) | Character |
boolean(未定) | Boolean |
说到包装器类型,有必要研究下拆箱和装箱的问题。
为什么要有拆箱装箱呢? 我的理解是,基本类型用起来简单,但是他们不是对象,无法提供相应类型的数据的处理方法。所以我们需要装箱操作,将基本类型转换成相应的包装器类型。 但是对于算数运算(只是其中一种需求),需要使用基本类型,这时候就需要拆箱,将包装器类型转换成基本类型。(JDK1.5之后,拆箱装箱都是自动的了)
我们以int和Integer为例,来研究下装箱和拆箱的实现过程:
Integer i =
new
Integer(
10
); //手动装箱
integer i = 10; //自动装箱
自动装箱,实际上调用的是Integer类的valueOf方法,这个方法是个静态方法,并且有多个重载,我们只看其中一个:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
这个实现有点特殊,如果输入i的值在-128到127之间,它从cache中直接返回对象,否则返回新对象(这个实现导致的结果,很容易出现的面试中哦!)
自动拆箱操作,调用的是intValue这个方法,它的实现如下:
private final int value;
/**
* Constructs a newly allocated {@code Integer} object that
* represents the specified {@code int} value.
*
* @param value the value to be represented by the
* {@code Integer} object.
*/
public Integer(int value) {
this.value = value;
}
有一些面试的坑,详见 https://www.cnblogs.com/dolphin0520/p/3780005.html
什么时候会自动拆箱呢:
算数运算时
==运算时,如果 a 和 b 都是Integer类型,则不会拆箱,因为==也可以直接比较对象,表示a和b是否指向同一对象地址。因此这里并不是比较值是否相等了。而如果a 和 b 中有一个是int类型,另一个是Integer 类型,则会触发拆箱,然后对两个int值进行比较
几乎所有的运算符都只能操作基本类型。 唯一的例外是 = == !=, 他们能操作所有类型, 此外,String类型支持+和+=
byte short char 参加算数运算时,总是首先自动提升为int。
为什么要分基本类型和引用类型呢?? 我的理解是,引用类型的实例是放到堆中的,只是其引用被放在了变量中。对于很小的对象,如果都放置于堆中对性能是有影响的。 而基本类型保存的是其实际的值。
引用类型不能直接参与算数运算,儿必须调用其相应的方法