自动装箱、拆箱与遍历循环(Foreach循环)

看如下例子:包含了自动装箱、拆箱以及foreach循环的过程

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4);
    // 如果在JDK 1.7中,还有另外一颗语法糖 ,
    // 能让上面这句代码进一步简写成List<Integer> list = [1, 2, 3, 4];
    int sum = 0;
    for (int i : list) {
        sum += i;
    }
    System.out.println(sum);
}

上面的程序内部编译后如下:

public static void main(String[] args) {
    List list = Arrays.asList( new Integer[] {
         Integer.valueOf(1),
         Integer.valueOf(2),
         Integer.valueOf(3),
         Integer.valueOf(4) });

    int sum = 0;
    for (Iterator localIterator = list.iterator(); localIterator.hasNext(); ) {
        int i = ((Integer)localIterator.next()).intValue();
        sum += i;
    }
    System.out.println(sum);
}

上述代码一共包含了泛型、自动装箱、自动拆箱、遍历循环与变长参数5中语法糖,第二份代码是他们编译后的变化。泛型在编译过程中会进行擦除,将泛型参数去除;自动装箱、拆箱在变之后被转化成了对应的包装盒还原方法,如Integer.valueOf()与Integer.intValue()方法;而遍历循环则被还原成了迭代器的实现,这也是为什么遍历器循环需要被遍历的类实现Iterator接口的原因。

这些语法糖虽然看起来很简单,但也有一些应该注意容易犯错的地方。看如下代码:

public static void main(String[] args) {
    Integer a = 1;
    Integer b = 2;
    Integer c = 3;
    Integer d = 3;
    Integer e = 321;
    Integer f = 321;
    Long g = 3L;
    System.out.println(c == d);
    System.out.println(e == f);
    System.out.println(c == (a + b));
    System.out.println(c.equals(a + b));
    System.out.println(g == (a + b));
    System.out.println(g.equals(a + b));
    String str1 = "hello";
    String str2 = "hello";
    System.out.println(str1 == str2);
}
运行结果:
true
false
true
true
true
false
true

首先注意两点:

  • “==”运算在不遇到算术运算的情况下不会自动拆箱
  • equals()方法不处理数据转型的问题。

分析:

  • 为什么会出现c == d为true,e==f为false的原因?First,Integer c = 3这句代码的内部实现是Integer c = Integer.valueOf(3),那么接下我们看一下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);
}

static final int low = -128;
static final int high = 127;

从上面代码可以知道,在Java运行时内存的常量池里面有一个int类型的常量池,常量池里数据的大小在-128~127之间。所以c和d都指向常量池里的同一个数据。

  • 为什么g == (a + b)为true,而g.equals(a + b)为false?
    首先Long.longValue(g) == (a + b)编译后为g.longValue() == (long)(Integer.intValue(a) + Integer.intValue(a)),由于包装类的”==”右边遇到了运算符,所以对于”==”左边的Long型会自动拆箱为long基本数据类型,而右边首先对a、b进行自动拆箱,相加后自动类型转换为long型。所以输出为true。

    而对于g.equals(a + b)而言,a+b直接自动拆箱进行相加,之后进行装箱为Integer类型,不同类型的包装类不能相互转换,而Long的equals()方法的不处理数据类型的转型关系。实现如下:

public boolean equals(Object obj) {
    if (obj instanceof Long) {
        return value == ((Long)obj).longValue();
    }
    return false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值