包装类的学习

参考 一文读懂什么是Java中的自动拆装箱

基本数据类型

  • java中数值类型不错在无符号数,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变(貌似和C++不同)
  • 使用基本类型,基本类型都是在栈上创建的,不像java对象要在堆上创建,比较笨重

为什么需要包装类

因为Java是一种面向对象语言,很多地方都需要使用对象而不是基本数据类型。比如,在集合类中,我们是无法将int 、double等类型放进去的。因为集合的容器要求元素是Object类型。为了让基本类型也具有对象的特征,就出现了包装类型,它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。

自动装箱的底层原理

(我照着原博主的方法测试,但是反编译没有看到装箱和拆箱的代码,还是太菜)
原java代码
public static  void main(String[]args){
    Integer integer=1; //装箱
    int i=integer; //拆箱
}

反编译后的class文件
public static  void main(String[]args){
    Integer integer=Integer.valueOf(1); 
    int i=integer.intValue(); 
}

通过博主的总结,基本上自动装箱都是通过包装类的valueOf()方法来实现的.自动拆箱都是通过包装类对象的xxxValue()来实现的

自动装箱和拆箱的发生场景

  • 将基本类型往集合中加入
  • 包装类型 和 基本类型之间的比较
Integer i = new Integer(5);
boolean flag = (i>10)?false:true;
  • 包装类型的四则运算,先拆包为基本类型,在进行运算,如果返回值又是包装类,再自动装箱
  • 三目运算符潜在的自动装箱和拆箱
同样我试了sts eclipse反编译插件,始终不能显示装箱和拆箱的语句,那就只能用作者的例子
源代码:
boolean flag = true;
Integer i = 0;
int j = 1;
int k = flag ? i : j;
反编译:
boolean flag = true;
Integer i = Integer.valueOf(0);
int j = 1;
int k = flag ? i.intValue() : j;
System.out.println(k);

java中对于三目运算符有一个要求,这其实是三目运算符的语法规范。
当第二,第三位操作数分别为基本类型和对象时,其中的对象就会拆箱为基本类型进行操作。

因为例子中,flag ? i : j;片段中,
第二段的i是一个包装类型的对象,而第三段的j是一个基本类型,
所以会对包装类进行自动拆箱。如果这个时候i的值为null,那么久会发生空指针异常!



原作者提出一个例子,避免出现自动拆箱可能导致的异常,
我感觉比上面这个例子更好理解三目运算符这种约束的潜在错误的可能性


原作者的例子

自动拆装箱与缓存

public static void main(String... strings) {

    Integer integer1 = 3;
    Integer integer2 = 3;

    if (integer1 == integer2)
        System.out.println("integer1 == integer2");
    else
        System.out.println("integer1 != integer2");

    Integer integer3 = 300;
    Integer integer4 = 300;

    if (integer3 == integer4)
        System.out.println("integer3 == integer4");
    else
        System.out.println("integer3 != integer4");

}

Integer的比较面试题,估计都碰到过,但是如何调整,我还真不知道


作者原话
我们只需要知道,当需要进行自动装箱时,如果数字在-128至127之间时,会直接使用缓存中的对象,而不是重新创建一个对象。

其中的javadoc详细的说明了缓存支持-128到127之间的自动装箱过程。最大值127可以通过-XX:AutoBoxCacheMax=size修改。

实际上这个功能在Java 5中引入的时候,范围是固定的-128 至 +127。后来在Java 6中,可以通过java.lang.Integer.IntegerCache.high设置最大值。

在jdk中默认的缓存机制为:
-128至127之间的整数

true 和 false的布尔值 

‘\u0000’至 ‘\u007f’之间的字符  ->即是ascii字符,老实说,我还是头一次知道



public class testBoxing {
	public static  void main(String[]args){
			Character  c1 = 'c';
			Character c2 = 'c';

		    if (c1 == c2)
		        System.out.println("c1 == c2");
		    else
		        System.out.println("c1 != c2");

		    Character c3 = '\u0081';
		    Character c4 = '\u0081';

		    if (c3 == c4)
		        System.out.println("c3 == c4");
		    else
		        System.out.println("c3 != c4");
	}
}
运行结果:
c1 == c2
c3 != c4

自动拆装箱带来的问题

  • 包装对象的数值比较,不能简单的使用==,虽然-128到127之间的数字可以,但是这个范围之外还是需要使用equals比较。
在Integer中equals写法:equals还是主要依赖基本类型的数值,但是我觉得还是都用equals比较好,==这种奇巧淫技稍微一疏忽,就会导致错误逻辑
    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }
  • 前面提到,有些场景会进行自动拆装箱,同时也说过,由于自动拆箱,如果包装类对象为null,那么自动拆箱时就有可能抛出NPE。

  • 如果一个for循环中有大量拆装箱操作,会浪费很多资源。

猜你喜欢

转载自blog.csdn.net/whp404/article/details/82991439
今日推荐