经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
Java日常错误及需要注意细节,持续更新......
来源:cnblogs  作者:那股泥石流  时间:2018/10/12 9:49:33  对本文有异议

记录日常工作中一些容易被忽视的错误及细节,持续更新......

一、问题:HashMap<Long, String>中,用get(Integer key)取不到值

  1. Map<Long, String> map = new HashMap<Long, String>();
  2. map.put(1L, "1");
  3. System.err.println(map.get(1));// null
  4. System.err.println(map.get(1L));// 1

1.首先想到Long与Integer的hashCode方法不同,Integer-value   Long-(int)(value ^ (value >>> 32))

但是!!计算出的hashCode值是相同的,不是问题所在

2.查看HashMap源码:注意加亮部分

  先比较key.hash,然后first.key == key || key.equals(first.key)

  1.      /**
  2. * 先比较key.hash,然后first.key == key || key.equals(first.key)
  3. */
  4. final Node<K,V> getNode(int hash, Object key) {
  5. Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
  6. if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) {
  7. if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k))))
  8. return first;
  9. if ((e = first.next) != null) {
  10. if (first instanceof TreeNode)
  11. return ((TreeNode<K,V>)first).getTreeNode(hash, key);
  12. do {
  13. if (e.hash == hash &&
  14. ((k = e.key) == key || (key != null && key.equals(k))))
  15. return e;
  16. } while ((e = e.next) != null);
  17. }
  18. }
  19. return null;
  20. }

 先看first.key == key:"=="比较地址值,l是Long cache[]中的1,o是Integer cache[]中的1,false

  1. Long l = 1L;
  2. Object o = 1;
  3. System.err.println(l == o);// false
  4. // 反编译后:
  5. Long l = Long.valueOf(1L);
  6. Object o = Integer.valueOf(1);
  7. System.err.println(l == o);

然后看key.equals(first.key):先检查类型,false

  1. //Long的equals方法
  2. public boolean equals(Object obj) {
  3. if (obj instanceof Long) {
  4. return value == ((Long)obj).longValue();
  5. }
  6. return false;
  7. }

引发新的问题:为什么这个是true?——反编译解决

  1. Long l = 1L;
  2. System.err.println(l == 1);// true
  3. // 反编译后:
  4. Long l = Long.valueOf(1L);
  5. System.err.println(l.longValue() == 1L);//编译器直接将1转成1L

 二、两个值相等的Integer不“==”

  1. Integer c = 99999;
  2. Integer d = 99999;
  3. System.out.println(c == d);// false

 Integer c = 99999;// 反编译:Integer c = Integer.valueOf(99999);

查看Integer源码:

-128 <= i <= 127时,直接在Integer cache[]中取;否则,new Integer(i)

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

结论:

  1. int a = 99999;
  2. int b = 99999;
  3. System.err.println(a == b);// true
  4. Integer c = 99999;
  5. Integer d = 99999;
  6. System.out.println(c == d);// false
  7. Integer e = 127;
  8. Integer f = 127;
  9. System.out.println(e == f);// true

 三、List.remove()方法调用错误

注意list两个remove方法,remove(int index)  remove(Object o)

  1. public static void main(String[] args) {
  2. List<Integer> list = new LinkedList<Integer>();
  3. for (int i = 0; i < 9999999; i++) {
  4. list.add(i);
  5. }
  6. // remove(int index)
  7. long before = System.currentTimeMillis();
  8. int i = 8888888;
  9. list.remove(i);
  10. long after = System.currentTimeMillis();
  11. System.err.println("index=" + (after - before));// 6ms
  12. // remove(Object o)
  13. long before = System.currentTimeMillis();
  14. Integer i = 8888888;
  15. list.remove(i);
  16. long after = System.currentTimeMillis();
  17. System.err.println("Object=" + (after - before));// 96ms
  18. }

四、三目运算符与自动拆装箱

  1. Map<String,Boolean> map = new HashMap<String, Boolean>();
  2. Boolean b = (map!=null ? map.get("test") : false);// Exception in thread "main" java.lang.NullPointerException

查问题:

  NullPointerException找不出原因

  反编译看: ((Boolean)map.get("test")) == null

  1. HashMap map = new HashMap();
  2. Boolean boolean1 = Boolean.valueOf(map == null ? false : ((Boolean)map.get("test")).booleanValue());

结论:

  三目运算符的语法规范,参见 jls-15.25

  三目运算符 当第二,第三位操作数分别为基本类型和对象时,其中的对象就会拆箱为基本类型进行操作。

以后注意:

1、保证三目运算符的第二第三位操作数都为对象类型

  1. Map<String,Boolean> map = new HashMap<String, Boolean>();
  2. Boolean b = (map!=null ? map.get("test") : Boolean.FALSE);

 2、自动拆装箱问题

  1. Integer integer = 1; // 装箱 Integer integer=Integer.valueOf(1); new Integer()
  2. int i = integer; // 拆箱 int i=integer.intValue();

 

1)包装对象的数值比较,不能简单的使用==(只有-128到127之间IntegerCache内的数字可以,但是这个范围之外还是需要使用equals比较)。

2)自动拆箱,如果包装类对象为null,那么自动拆箱时就有可能抛出NPE。

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

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号