java语法糖

1. 自动装箱、拆箱

在《深入理解Java虚拟机》的语法糖这一章节中,看到了一个关于Java中自动装箱与拆箱的机制。书中有一个例子如下:

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));
    }

最开始,本着==判断的都是引用,equals判断的都是值的方式,初步判断的结果为:

false
false
false
true
false
false

但是运行之后的结果为:

true
false
true
true
true
false

当时就大吃一惊,后来通过查资料发现原因如下(也可以通过javap反编译查看):

注:Integer.valueOf()方法是装箱的体现,Integer.intValue()方法是拆箱的体现。

上面的代码等价于以下代码:

    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));
        Integer a = Integer.valueOf(1);
        Integer b = Integer.valueOf(2);
        Integer c = Integer.valueOf(3);
        Integer d = Integer.valueOf(3);
        Integer e = Integer.valueOf(321);
        Integer f = Integer.valueOf(321);
        Long g = Long.valueOf(3L);
        
        System.out.println(c == d);
        System.out.println(e == f);
        System.out.println(c.intValue() == (a.intValue() + b.intValue()));
        System.out.println(c.equals(Integer.valueOf(a.intValue() + b.intValue())));
        System.out.println(g.longValue() == Integer.valueOf((a.intValue() + b.intValue())));
        System.out.println(g.equals(Integer.valueOf(a.intValue() + b.intValue())));
        
    } 

原因如下:

  1. 包装类的==运算在不遇到算术运算符的情况下不会自动拆箱
  2. 包装类的equals()方法不处理数据类型转换的关系。下面是equals的源码:(即如果传入对象不和自己类型一样,直接返回false,这个编码规则在《Effective Java》中也有提到。)
public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

还有一个问题,那为什么有c==d 结果为true,而e==f的结果为false呢?

因为在JavaInteger实现中,默认已经将Java的[-128, 127]的数据放入缓存中,需要的时候直接在缓存中取就可以了,超过这个范围的才会新生成对象,因此cd为缓存中的相同对象,但是ef为新生成的对象。

以下是JDK中的源码:

//static final int low = -128;
//static final int high;
//static final Integer cache[];

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

2 条件编译

许多程序设计语言都提供了条件编译的途径,如C、C++ 中使用预处理器指示符(#ifdef)完成条件编译。C、C++ 的预处理器最初的任务是解决编译时的代码依赖关系(如#include),而在 Java 语言之中并没有使用预处理器,因为 Java 语言天然的编译方式(不一个个编译 Java 文件,而是将所有编译单元的语法树顶级结点输入到待处理列表后再进行编译,因此各个文件之间能够互相提供符号信息) 无需使用预处理器。

Java 语言也可以进行条件编译,方法就是使用条件为常量的 if 语句。如下面代码:

public static void main(String[] args) {
		if(true){
			System.out.println("block 1");
		}else{
			System.out.println("block 2");
		}
}

编译后Class文件的反编译结果:

public static void main(String args[])
{
		System.out.println("block1");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值