认识 Java 的整形数据结构
本文分享自华为云社区《【Java】对基本类型-整型数据结构的认识》,作者: huahua.Dr 。
整型数据类型有两个:基本类型和引用类型(包装类)
整数型基本类型:byte,int,short,long
其引用类型:Byte,Integer,Short,Long
他们之前主要的区别在于:
存储占用的空间不同,分别是 1,2,4,8 个字节(每个字节占用 8bit),
java 里面整数型默认使用的 int 数据类型,即如果直接写整数字面量时,它表示的就是 int 类型,
整数型数据类型之间可以相互转换,以 int 为默认中间类型,定义了一个整数值 4,可以直接赋值给 int,
也可以直接赋值给 short 和 byte(只要数值范围不超过 byte 和 short 的存储范围,可以自动向下转型为 byte 或者 short;如果超过则需要强转但超过的高位数会丢失),也可以直接赋值给 long,不需要强转,会自动向上转型。
long 数据类型可以直接使用 L 或 l 声明
他们之间可以直接转,只要数值范围大于等于它的数值范围,都可以直接转;如果小于它的数值范围就需要强转,但强转会导致数值丢失,编译并不会报错。
其他的基本相同;因此我们以 int 类型来展开详细说明。
java 中一切都是对象,为什么 int 不用创建对象实例化,而可以直接使用?
单纯是为了编程方便,引入基本类型。
既然引入了基本对象,那也不能破坏 java 是一个操作对象的语言吧?
所以后面引入了包装类(wrapper class),为每种基本类型都引入了其对应的包装类型,int 基本类型的包装类型就是 Integer 对象。
基本类型引入了包装类型就能将,int 基本类型就能像操作对象一样去操作了吗?
是的,还 Java1.55 引入了一个机制:自动拆箱和自动装箱,使得基本类型和其对应的包装类型可以相互转换,原始基本类型可以自动转换成对应的包装对象。
基本类型和包装类型是何时进行相互转化,如何相互转换?
自动拆箱与装箱机制,可以在 java 变量赋值或者方法调用传值与返回值或者容器存储数据时直接使用基本类型或者对应的包装类型;在 java 1.5 版本之前,使用容器集合(Collection)存储数据时,只能存储引用类型,需要存储基本类型,则需要先将其转成其对应的包装类型才可以。
自动装箱就是 java 自动的将基本类型数值转换成其对应的包装类型,自动装箱时编译器会自动调用其包装类的 valueOf()方法将基本类型数值转成对象。
自动拆箱就是 java 自动将包装类型转换成其对应的基本类型,自动拆箱时编译器会自动调用其包装类的 xxxValue()方法:如 intValue()\doubleValue()\longValue()等将对象转成基本类型数值。
当基本数据数值与包装类型进行运算时,会触发自动拆箱。
例子:
//before autoboxing
Integer iObject = Integer.valueOf(3);
Int iPrimitive = iObject.intValue()
//after java5
Integer iObject = 3; //autobxing - primitive to wrapper conversion
int iPrimitive = iObject; //unboxing - object to primitive conversion
public static Integer show(Integer iParam){
System.out.println("autoboxing example - method invocation i: " + iParam);
return iParam;
}
//autoboxing and unboxing in method invocation
show(3); //autoboxing
int result = show(3); //unboxing because return type of method is Integer
那自动拆箱和装箱那么方便,它有什么缺点吗?
由于编译器的介入,增加了操作步骤和工作量,如果频繁自动拆箱和装箱,会影响程序性能:
Integer sum = 0;
for(int i=1000; i<5000; i++){
sum+=i;
}
上面的代码 sum+=i 可以看成 sum = sum + i,但是+这个操作符不适用于 Integer 对象,首先 sum 进行自动拆箱操作,进行数值相加操作,最后发生自动装箱操作转换成 Integer 对象。其内部变化如下:
int result = sum.intValue() + i;
Integer sum = new Integer(result);
由于我们这里声明的 sum 为 Integer 类型,在上面的循环中会创建将近 4000 个无用的中间 Integer 对象,在这样庞大的循环中,会降低程序的性能并且加重了 GC 垃圾回收的工作量。因此在我们编程时,需要注意到这一点,正确地声明变量类型,避免因为自动装箱引起的性能问题。
还有一个问题:如果 int 与 Integer 混用,Integer 自动拆箱成 int 时,会调用 Integer.intValue()方法进行拆箱,如果 Integer 赋值为 null,M 那么此时就会出现空指针异常。
如果一个类中有两个重载方法,一个重载方法的参数是 int 基本类型,一个是 Integer 引用类型,那么调用该方法时,会自动拆箱或装箱吗,实际会调用到那个方法?
Java1.5 之前肯定是会根据实际参数是基本类型还是引用类型来选择对应的方法;但是 java1.5 之后,有了自动拆箱和装箱机制之后,也是不会触发该机制的。也是根据实际参数类型来选择对应的方法调用。下面我们用实际代码来说明一下:
public class Test {
public static void main(String[] args) throws FileNotFoundException {
Test test = new Test();
int para1 = 12;
Integer para2 = 12;
test.test(12);
test.test(para2);
}
public void test(int para1) {
System.out.println("我的参数是 int 基本类型,值:"+para1);
}
public void test(Integer para2) {
System.out.println("我的参数是 Integer 类型,值:"+para2);
}
}
输出:
我的参数是 int 基本类型,值:12
我的参数是 Integer 类型,值:12
那么基本类型 int 与包装类型 Integer,数值进行比较是否相等会出现什么情况?
情况有三种:==比较的是地址,对象 Object 的 equals 方法比较的也是地址,只不过包装类型重写了 Object 方法,比较的数值。
int 与 int 比较是否相等,使用==进行两个数值相等的 int 比较,结果是 true
Integer 与 Integer 比较是否相等,-128 到 127 的 Integer 两个数值相等的对象使用==比较结果是 true,应为 JVM 为了省内存会将该范围的数值缓存起来,共用一个 Integer 对象;该范围以外的==比较结果是 false;如果都是重新 new 的两个数值相等的 Integer 对象,==也是 false,需要使用 Integer 对象的 equals 方法,比较才是 true,
int 与 Integer 比较是否相等,Integer 会自动拆箱,返回的结果是 true.
// Example 1: == comparison pure primitive – no autoboxing
int i1 = 1;
int i2 = 1;
System.out.println("i1==i2 : " + (i1 == i2)); // true
// Example 2: equality operator mixing object and primitive
Integer num1 = 1; // autoboxing
int num2 = 1;
System.out.println("num1 == num2 : " + (num1 == num2)); // true
// Example 3: special case - arises due to autoboxing in Java
Integer obj1 = 1; // autoboxing will call Integer.valueOf()
Integer obj2 = 1; // same call to Integer.valueOf() will return same
// cached Object
System.out.println("obj1 == obj2 : " + (obj1 == obj2)); // true
// Example 4: equality operator - pure object comparison
Integer one = new Integer(1); // no autoboxing
Integer anotherOne = new Integer(1);
System.out.println("one == anotherOne : " + (one == anotherOne)); // false
int num3 = 129;
Integer obj3 = 129;
System.out.println("num3==obj3:"+(num3==obj3));// true
版权声明: 本文为 InfoQ 作者【华为云开发者联盟】的原创文章。
原文链接:【http://xie.infoq.cn/article/9b3e8741872d89e80c2a57a7b】。文章转载请联系作者。
评论