相关阅读
【小家java】java5新特性(简述十大新特性) 重要一跃
【小家java】java6新特性(简述十大新特性) 鸡肋升级
【小家java】java7新特性(简述八大新特性) 不温不火
【小家java】java8新特性(简述十大新特性) 饱受赞誉
【小家java】java9新特性(简述十大新特性) 褒贬不一
【小家java】java10新特性(简述十大新特性) 小步迭代
##1、概述
此篇博文没有具体的主题,主要针对于平时开发过程中遇到的一些小问题的记录,并且大都从源码的角度去解释为什么会报错。并且此篇博文是持续更新中。。。
##2、栗子
1、包装类型的的> < =的比较
public static void main(String[] args) { Integer i = null; Integer i2 = null; System.out.println(i < i2); //java.lang.NullPointerException }
包装类型能用比较运算符的根本原因:JDK5的自动拆箱。因此如果是是null的话,自动拆箱就报错了。所以在日常使用的时候一定要注意。特别是Interger和int比的时候,如果Interger为null,那必然空指针。从代码角度看是因为自动拆箱JVM会调用Interger的.intValue()方法,所以如果是null,就挂了
2、关于int值比较的一些问题
在日常编码中,经常会遇到Interger的比较问题(比如id相等),看下面例子
public static void main(String[] args) { Integer i1 = 100; Integer i2 = 100; System.out.println(i1 == i2); //true Integer i3 = 200; Integer i4 = 200; System.out.println(i3 == i4); //false }
我们知道,对象比较用==的话比较的是地址值,所以咱们看看两者的地址值哈。
public static void main(String[] args) { Integer i1 = 100; Integer i2 = 100; System.out.println(System.identityHashCode(i1)); //2093631819 System.out.println(System.identityHashCode(i2)); //2093631819 Integer i3 = 200; Integer i4 = 200; System.out.println(System.identityHashCode(i3)); //2074407503 System.out.println(System.identityHashCode(i4)); //999966131 }
各位看官,应该看出端倪了吧,这就是为什么第一个是true,第二个为false的最直接原因,但还不是最根本原因,下面容我介绍一下最根本原因,Interger内部有如下代码:
同理Long里面一样
如图可以看出,Interger在初始化的时候内部就维护了一个缓存:-128到127对象都给Cache了,所以当我们向上转型这些对象时,没有new而是从缓存拿的,所以就是上面的答案。当然,我们必须清楚,其实JVM自动装箱调用了valueOf方法:
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
我们发现,没有new而是从缓存拿,因此内存地址值肯定一样的。所以可以很好理解下面这两个现象了:
public static void main(String[] args) { Integer i1 = new Integer(100); Integer i2 = new Integer(100); System.out.println(i1 == i2); //false 因为用了new关键字,一定开辟新内存的 Integer i3 = new Integer(200); Integer i4 = new Integer(200); System.out.println(i3 == i4); //false }
这样比较也没有问题:
public static void main(String[] args) { int i1 = 100; int i2 = 100; System.out.println(i1 == i2); //true int i3 = 200; int i4 = 200; System.out.println(i3 == i4); //true }
所以,综上所述,同类型的包装类型比较的时候,建议使用equals()方法。但是此处提醒一点:不同类型的equals肯定是false的,比如Interger和Long的对比,不要这么来:
public static void main(String[] args) { Integer i1 = 100; Long i2 = 100L; System.out.println(i1.equals(i2)); //false }
这个虽然值一样,但结果肯定false。这里我贴一处源码,大家就能了解了:
我们发现他们都重写了equals方法,而类型相同是第一必须。so,以后比较的时候一定要注意类型一致啊
3、intValue(),Integer.valueOf(String s)和Integer.parseInt(String s)有什么区别?
intValue()是把Integer对象类型变成int的基础数据类型; //一般由jvm自己调用
静态方法parseInt()是把String 变成int的基础数据类型;
静态方法valueOf()是把给定的String参数转化成Integer对象类型,依赖于parseInt()方法;
然后如果想得到一个小的Integer对象,但是Integer.valueOf的效率比new的效率高,因为valueOf有缓存。
综上所述,一般用Integer.parseInt(str),除非你要返回Integer类型,不然还有封装拆箱,性能多少会耗费些。
##3、使用场景
持续更新中。。。
##4、最后
整理出来的都是一些小细节,希望能帮助到大家