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

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

        Map<Long, String> map = new HashMap<Long, String>();map.put(1L, "1");System.err.println(map.get(1));// nullSystem.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)

     /*** 先比较key.hash,然后first.key == key || key.equals(first.key)*/final Node<K,V> getNode(int hash, Object key) {Node<K,V>[] tab; Node<K,V> first, e; int n; K k;if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) {if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k))))return first;if ((e = first.next) != null) {if (first instanceof TreeNode)return ((TreeNode<K,V>)first).getTreeNode(hash, key);do {if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;} while ((e = e.next) != null);}}return null;}

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

        Long l = 1L;Object o = 1;System.err.println(l == o);// false// 反编译后:Long l = Long.valueOf(1L);Object o = Integer.valueOf(1);System.err.println(l == o);

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

        //Long的equals方法public boolean equals(Object obj) {if (obj instanceof Long) {return value == ((Long)obj).longValue();}return false;}

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

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

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

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

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

查看Integer源码:

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

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

结论:

        int a = 99999;int b = 99999;System.err.println(a == b);// true
Integer c = 99999;Integer d = 99999;System.out.println(c == d);// false
        Integer e = 127;Integer f = 127;System.out.println(e == f);// true    

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

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

    public static void main(String[] args) {List<Integer> list = new LinkedList<Integer>();for (int i = 0; i < 9999999; i++) {list.add(i);}// remove(int index)long before = System.currentTimeMillis();int i = 8888888;list.remove(i);long after = System.currentTimeMillis();System.err.println("index=" + (after - before));// 6ms// remove(Object o)long before = System.currentTimeMillis();Integer i = 8888888;list.remove(i);long after = System.currentTimeMillis();System.err.println("Object=" + (after - before));// 96ms
        }

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

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

查问题:

  NullPointerException找不出原因

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

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

结论:

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

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

以后注意:

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

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

2、自动拆装箱问题

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

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

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

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

五、switch语句忘记break

本来我跟你现在想的一样,一定不会忘,直到遇到了这个问题。

        int i = 3;switch (i) {case 1:System.out.println(1);break;case 2:System.out.println(2);break;case 3:System.out.println(3);// 没有break, 不会有问题}

当你需要在之后接着case的时候,直接复制case 3,就bug了。

(1)case完一定break,除非特别需要穿透到下一个case;

(2)复制代码前后都要检查是否有问题。

六、数值溢出问题

    // 为了更好的展示问题,代码举出的是较极端的情况public void overFlow(int a) {int b = 999999 * a; // 6个9 int最大值=2147483647int limit = 999999999; // 9个9if (b < limit) {System.out.println("a*b小于limit");}}

如果a传入一个较大的int值,a*999999之后会超过int的最大值

而默认结果是int类型,会将a*999999的结果强转成int,导致不是想要的结果的结果

即使a*999999是大于limit的,强转成int后,b可能会比limit小,甚至可能是负数

解决:

    // 用long类型计算(还会用一定风险)public void overFlow(int a) {long b = 999999L * a;int limit = 999999999;if (b < limit) {System.out.println("a*999999小于limit");}}// 将加法和乘法转变成减法和除法运算public void overFlow(int a) {int limit = 999999999;if (a < limit/999999) {System.out.println("a*999999小于limit");}}

七、对象引用问题

public static void main(String[] args) {Map<Integer, Inner> map = new HashMap<Integer, Inner>();// inner1.list [1]Inner inner1 = new Inner(new LinkedList<Integer>());inner1.getList().add(1);map.put(1, inner1);// inner2.list [1, 2]Inner inner2 = new Inner(map.get(1).getList());inner2.getList().add(2);map.put(2, inner2);for (Entry<Integer, Inner> entry : map.entrySet()) {System.err.println("" + entry.getKey() + " " + entry.getValue().getList());}/*** 目的:inner1.list [1]   inner2.list [1, 2]* 结果:inner1.list [1, 2]   inner2.list [1, 2]*/}static class Inner {List<Integer> list;public List<Integer> getList() {return list;}public Inner(List<Integer> list) {this.list = list;}}

分析:

1.将inner1.list的引用给了inner2.list,nner1.list inner2.list指向的是同一个List。

2.很简单的问题,开发时习惯了构造方法里这样写:this.list = list;

解决:

this.list = list;  改成   this.list = new LinkedList<Integer>(list);

转载于:https://www.cnblogs.com/hexinwei1/p/9720310.html

Java日常错误及需要注意细节,持续更新......相关推荐

  1. 普元EOS开发积累第一篇(常见错误解决方法) 持续更新

    普元EOS开发积累第一篇(常见错误解决方法) 持续更新 参考文章: (1)普元EOS开发积累第一篇(常见错误解决方法) 持续更新 (2)https://www.cnblogs.com/tangjing ...

  2. 2021最新Java面经系列整理,持续更新

    2021最新Java面经系列整理,持续更新... 欢迎大家关注收藏,一起加油O(∩_∩)O哈~ 2021最新Java面经系列 系列 内容 地址 框架篇 2021最新Java面经整理 | 框架篇(一)S ...

  3. JAVA学习视频及资料地址-持续更新

    JAVA学习 JAVA学习路线 https://blog.csdn.net/java1856905/article/details/89474640 狂神说笔记大全 狂神说Java Mybatis笔记 ...

  4. 新鲜出炉java后端高频面经总结-持续更新中(万字长文,助君青云)

    文章目录 java java基础 数据类型 基本数据类型 引用类型 Integer 关键字 static-静态属性 abstract-抽象 extends-继承 多态 interface-接口 Ref ...

  5. Java面试宝典简洁篇(持续更新中,从入门到放弃)

    Java基础 1.Hashcode()和 equals()和==区别?  1.hashcode()方法跟 equals()在 java 中都是判断两个对象是否相等 2.两个对象相同,则 hashcod ...

  6. Java工作面试必问(持续更新)

    SSM  1. GET和POST请求的区别? ① GET(获取&检索)从服务器上获取数据. ① POST(创建&更新)向服务器传送数据. 误区:不是获取数据只能用GET,只是通常用GE ...

  7. 初级Java应届生面试题(持续更新。。。)

    初级Java应届生面试题 初识Java 1.Write Once,Run Anywhere 2.为什么要配置path环境变量?如何配置? 3.编写代码,使得发生VirtualMachineExcept ...

  8. java史上最全面试题--持续更新中(一)

    1.面向对象的特征有哪些方面? 抽象:将同类对象的共同特征提取出来构造类. 继承:基于基类创建新类. 封装:将数据隐藏起来,对数据的访问只能通过特定接口. 多态性:不同子类型对象对相同消息作出不同响应 ...

  9. JAVA基础精选面试题(持续更新,一天五道,祝各位道友,早日飞升上仙)!

    1.重载和重写的区别? 重载发生在一个类中,同名的方法如果有不同的参数列表(类型不同.个数 不同.顺序不同)则视为重载. 重写发生在子类与父类之间,重写要求子类重写之后的方法与父类被重写方 法有相同的 ...

最新文章

  1. OpenAI解散机器人团队,曾试图造AGI机器人,创始人:最好的决定
  2. 具体解释Hibernate中的事务
  3. CentOS下用yum管理软件的好处
  4. 2020-12-14 Python PyCharm新建项目自动添加介绍和utf-8编码
  5. 【机器学习基础】数学推导+纯Python实现机器学习算法21:马尔可夫链蒙特卡洛...
  6. 简陋版C语言仿真通讯录之动态内存开辟版本
  7. linux查看某进程cpu使用情况,linux中如何查看进程对应的cpu使用情况?
  8. 用c语言输出1 n平方自然数魔方阵,用C语言求:打印出由1到n平方的自然数的魔方阵...
  9. 我的世界基岩版json_我的世界基岩版下载_我的世界基岩版app下载_我的世界基岩版官网最新版下载-新手游网...
  10. 关于CSS的fixed定位
  11. iphone11屏比例_iphone11pro屏幕尺寸比例
  12. 文件夹恶意软件WORM_AUTORUN.FIU处理
  13. 服务器win2003修复,win2003服务器svchost.exe异常
  14. 苹果手机itunes显示无法连接服务器,苹果手机无法连接到iTunes Store怎么办 连接失败解决方法...
  15. 程序员必须收藏的网站整理(持续更新)
  16. python招聘杭州拉勾网_Python爬取拉勾网招聘信息
  17. 大数据时代带来的伦理问题
  18. 无需下载 网页版 Matlab
  19. 【Python】利用Python实现精准三点定位(经纬度坐标与平面坐标转换法求解)
  20. 网络服务-DCHP原理与配置

热门文章

  1. 小米wifi每天晚上准时断网_小米 11再次确定,将于28日准时发布,售价更感人
  2. html ace编辑器,Tiny-editor
  3. docker 容器安装conposer_docker和php:将依赖项(composer)放入容器中
  4. linux设备模型的主要功能,Linux设备模型(3)
  5. html5 电流效果,在HTML5 Canvas 2D上绘制云雾中的电流动画特效
  6. sql server linux性能,详细了解SQL Server 2008性能和性能优化
  7. 如何在mysql中添加复选框_如何使用输入和复选框更新mysql
  8. 计算机上没有office2010,《我安装了office2010,为什么桌面-右键-新建中没有excel呢?》 excel文件找不到...
  9. 江西小学计算机说课稿,2019江西教师招聘面试-小学数学-说课稿
  10. axios获取图片显示_Vue.js+axios图片预览以及上传显示进度