免费在线网站建设/百度精简版入口
java常见面试考点
往期文章推荐:
java常见面试考点(一):自增变量
java常见面试考点(二):单例模式
java常见面试考点(三):类初始化与实例初始化
java常见面试考点(四):方法的参数传递机制
java常见面试考点(六):深入理解String类型
【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权);
本博客的内容来自于:java常见面试考点(五):基本类型和包装类型的区别;
学习、合作与交流联系q384660495;
本博客的内容仅供学习与参考,并非营利;
文章目录
- java常见面试考点
- 一、基本数据类型与包装类型
- 二、自动拆箱与装箱
- 1.拆箱与装箱
- 2.包装类的缓存问题
- 1. 实验一:基本数据类型的==比较会是怎么样?
- 2. 实验二:包装类的数据类型进行==比较会是怎么样?
- 3. 实验三:基本数据类型和包装数据类型比较结果会是怎么样?
- 三、总结
- 四、参考资料
一、基本数据类型与包装类型
基本类型 | 二进制位数 | 包装器类 |
---|---|---|
boolean | 1 | Boolean |
byte | 8 | Byte |
char | 16 | Character |
short | 16 | Short |
int | 32 | Integer |
long | 64 | Long |
float | 32 | Float |
double | 64 | Double |
1.基本数据类型出现的原因? 在Java编程思想的第一章就讲到:万物皆对象,new一个对象存储在堆中,我们通过堆栈的引用来使用这些对象,但是对于经常用到的一系列类型如int,如果我们用new将其存储在堆里就不是很有效——特别是简单的小的变量。所以就出现了基本类型,同C++一样,Java采用了相似的做法,对于这些类型不是用new关键字来创建,而是直接将变量的值存储在堆栈中,因此更加高效。
2,包装数据类型出现的原因?
Java是一个面向对象的语言,基本类型并不具有对象的性质,为了与其他对象“接轨”就出现了包装类型(如我们在使用集合类型Collection时就一定要使用包装类型而非基本类型),它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。同时也方便了向其他数据类型转换。
关于基本类型和包装类型的总结
- 基本类型的优势:数据存储相对简单,运算效率比较高。包装类的优势:和其他对象“接轨”,比如集合的元素必须是对象类型,满足了java一切皆是对象的思想,方便与其他数据类型转换;
- 声明方式不同,基本类型不适用new关键字,而包装类型需要使用new关键字来在堆中分配存储空间;
- 存储方式及位置不同,基本类型是直接将变量值存储在堆栈中,而包装类型是将对象放在堆中,然后通过引用来使用;
- 初始值不同,基本类型的初始值如int为0,boolean为false,而包装类型的初始值为null;
- 使用方式不同,基本类型直接赋值直接使用就好,而包装类型在集合如Collection、Map时会使用到;
二、自动拆箱与装箱
1.拆箱与装箱
装箱:
将基本数据类型封装为包装类对象,利用每一个包装类提供的构造方法实现装箱操作。
// 自动装箱
Integer integer1 = 1;
// 手动装箱
Integer integer1 = new Integer(1);
Integer integer1 = Integer.valueOf(1);
拆箱:
将包装类中包装的基本数据类型数据取出。
// 自动拆箱
int integer2 = integer1;
// 手动拆箱
int integer2 = integer1.intValue();
2.包装类的缓存问题
1. 实验一:基本数据类型的==比较会是怎么样?
int i1 = 127;
int i2 = 127;
System.out.println(" int和int进行==比较: " + (i1==i2));
//结果如下:int和int进行==比较: true
这里还是很容易理解的,基本数据类型是直接将变量值存储在堆栈中的,比较也是根据值进行比较。
2. 实验二:包装类的数据类型进行==比较会是怎么样?
Integer i3 = 127;
Integer i4 = 127;Integer i5 = new Integer(127);
Integer i6 = new Integer(127);
System.out.println(" Integer和Integer进行==比较: " + (i4==i3));
//Integer和Integer进行==比较: true
System.out.println(" Integer和Integer进行==比较: " + (i6==i5));
//Integer和Integer进行==比较: false
结果和你猜想的一样吗,为什么俩种方式结果却不一样呢?
首先Integer是对象,也就是说i3,i4,i5,i6变量里面存放的是什么?是值吗,当然不是,是地址!只不过Integer重写了toString()方法,如下所示:
public static String toString(int i) {if (i == Integer.MIN_VALUE)return "-2147483648";int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);char[] buf = new char[size];getChars(i, size, buf);return new String(buf, true);}
既然是比较地址,不同的对象应该有着不同的地址,那为什么上面Integer i3 = 127;这种方式比较的结果是true呢?
其实这里涉及到包装类的缓存问题,基本数据类型的自动装箱其实调用的是静态工厂方法valueOf(int i),下面看一下这个方法的源码
/*** Returns an {@code Integer} instance representing the specified* {@code int} value. If a new {@code Integer} instance is not* required, this method should generally be used in preference to* the constructor {@link #Integer(int)}, as this method is likely* to yield significantly better space and time performance by* caching frequently requested values.** This method will always cache values in the range -128 to 127,* inclusive, and may cache other values outside of this range.** @param i an {@code int} value.* @return an {@code Integer} instance representing {@code i}.* @since 1.5*/
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}
缓存池IntegerCache代码如下:
private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}private IntegerCache() {}}
从源码中可以看出,当数据在-128到127时,会从缓存池中取出对象,即取出的是同一个对象,而且cache数组是被final修饰,无法更改。同一个对象的引用其==当然为true了。而new Integer(127)方式是直接创建新的对象,i5,i6指向的不同的对象,结果自然为false了。
那么有哪些封装类型具有缓存呢
Byte缓存范围为-128到127
Short缓存范围-128到127
Integer默认缓存范围-128到127,可设置最大值,如:在VM中加入-Djava.lang.Integer.IntegerCache.high=1000,最大值就为1000
Long缓存范围-128到127
Character缓存范围0-127
注意Double和Float是没有缓存的
既然包装类的对象因为缓存原因不能直接用==比较,解决办法其实也有很多。
第一种: a.intValue()==b.intValue();
第二种: a.compareTo(b);
第三种:a.equals(b)
3. 实验三:基本数据类型和包装数据类型比较结果会是怎么样?
int i1 = 127;
Integer i2 = 127;
System.out.println("i1 == i2 " + (i1==i2));
// 输出:i1 == i2 true
看到这里,和你想的结果一样吗?是不是很奇怪为什么i1存放的数值,i2存放的地址,为什么最后结果居然为true?让我们用javap反编译看一下,反编译的结果如下所示:
public class Test {public Test();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: iconst_11: istore_12: iconst_13: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;6: astore_27: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;10: iload_111: aload_212: invokevirtual #4 // Method java/lang/Integer.intValue:()I15: if_icmpne 2218: iconst_119: goto 2322: iconst_023: invokevirtual #5 // Method java/io/PrintStream.println:(Z)V26: return
}
反编译的结果可以确定俩件事情:
- Integer i2 = 127;确实是调用了Integer.valueOf方法。
- Integer 变量==int 变量的时候,自动调用了Integer.intValue:();方法获取了
Integer的值。最后比较的实际是int和int进行比较,所以比较结果是true。
其实都是编译器帮我们完成了这些工作。
三、总结
所有的相同类型的包装类对象之间值的比较,全部使用equals()方法。
所有的POJO(简单Java类,只包含基本属性,有参构造,get/set)类属性必须使用包装类数据类型,类属性即static属性。
RPC(远程方法调用)方法返回值和参数必须使用包装数据类型。
推荐所有的局部变量使用基本数据类型。
建议大家再读一读这篇文章,看一看常见的面试问题:面试官:兄弟,说说基本类型和包装类型的区别吧,这里做一个小总结:
区别一:包装类型可以为 null,而基本类型不可以,那为什么 POJO 的属性必须要用包装类型呢?
《阿里巴巴 Java 开发手册》上有详细的说明:数据库的查询结果可能是 null,如果使用基本类型的话,因为要自动拆箱(将包装类型转为基本类型,比如说把 Integer 对象转换成 int 值),就会抛出 NullPointerException 的异常。
区别二:包装类型可用于泛型,而基本类型不可以。因为泛型在编译时会进行类型擦除,最后只保留原始类型,而原始类型只能是 Object 类及其子类——基本类型是个特例。
区别三:基本类型比包装类型更高效。基本类型在栈中直接存储的具体数值,而包装类型则存储的是堆中的引用。很显然,相比较于基本类型而言,包装类型需要占用更多的内存空间。假如没有基本类型的话,对于数值这类经常使用到的数据来说,每次都要通过 new 一个包装类型就显得非常笨重。
区别四:两个包装类型的值可以相同,但却不相等。这个上文已经解释的很清楚了。
四、参考资料
Java基本类型和包装类型总结
面试官:兄弟,说说基本类型和包装类型的区别吧