Java日常错误及需要注意细节,持续更新......
记录日常工作中一些容易被忽视的错误及细节,持续更新......
一、问题: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日常错误及需要注意细节,持续更新......相关推荐
- 普元EOS开发积累第一篇(常见错误解决方法) 持续更新
普元EOS开发积累第一篇(常见错误解决方法) 持续更新 参考文章: (1)普元EOS开发积累第一篇(常见错误解决方法) 持续更新 (2)https://www.cnblogs.com/tangjing ...
- 2021最新Java面经系列整理,持续更新
2021最新Java面经系列整理,持续更新... 欢迎大家关注收藏,一起加油O(∩_∩)O哈~ 2021最新Java面经系列 系列 内容 地址 框架篇 2021最新Java面经整理 | 框架篇(一)S ...
- JAVA学习视频及资料地址-持续更新
JAVA学习 JAVA学习路线 https://blog.csdn.net/java1856905/article/details/89474640 狂神说笔记大全 狂神说Java Mybatis笔记 ...
- 新鲜出炉java后端高频面经总结-持续更新中(万字长文,助君青云)
文章目录 java java基础 数据类型 基本数据类型 引用类型 Integer 关键字 static-静态属性 abstract-抽象 extends-继承 多态 interface-接口 Ref ...
- Java面试宝典简洁篇(持续更新中,从入门到放弃)
Java基础 1.Hashcode()和 equals()和==区别? 1.hashcode()方法跟 equals()在 java 中都是判断两个对象是否相等 2.两个对象相同,则 hashcod ...
- Java工作面试必问(持续更新)
SSM 1. GET和POST请求的区别? ① GET(获取&检索)从服务器上获取数据. ① POST(创建&更新)向服务器传送数据. 误区:不是获取数据只能用GET,只是通常用GE ...
- 初级Java应届生面试题(持续更新。。。)
初级Java应届生面试题 初识Java 1.Write Once,Run Anywhere 2.为什么要配置path环境变量?如何配置? 3.编写代码,使得发生VirtualMachineExcept ...
- java史上最全面试题--持续更新中(一)
1.面向对象的特征有哪些方面? 抽象:将同类对象的共同特征提取出来构造类. 继承:基于基类创建新类. 封装:将数据隐藏起来,对数据的访问只能通过特定接口. 多态性:不同子类型对象对相同消息作出不同响应 ...
- JAVA基础精选面试题(持续更新,一天五道,祝各位道友,早日飞升上仙)!
1.重载和重写的区别? 重载发生在一个类中,同名的方法如果有不同的参数列表(类型不同.个数 不同.顺序不同)则视为重载. 重写发生在子类与父类之间,重写要求子类重写之后的方法与父类被重写方 法有相同的 ...
最新文章
- OpenAI解散机器人团队,曾试图造AGI机器人,创始人:最好的决定
- 具体解释Hibernate中的事务
- CentOS下用yum管理软件的好处
- 2020-12-14 Python PyCharm新建项目自动添加介绍和utf-8编码
- 【机器学习基础】数学推导+纯Python实现机器学习算法21:马尔可夫链蒙特卡洛...
- 简陋版C语言仿真通讯录之动态内存开辟版本
- linux查看某进程cpu使用情况,linux中如何查看进程对应的cpu使用情况?
- 用c语言输出1 n平方自然数魔方阵,用C语言求:打印出由1到n平方的自然数的魔方阵...
- 我的世界基岩版json_我的世界基岩版下载_我的世界基岩版app下载_我的世界基岩版官网最新版下载-新手游网...
- 关于CSS的fixed定位
- iphone11屏比例_iphone11pro屏幕尺寸比例
- 文件夹恶意软件WORM_AUTORUN.FIU处理
- 服务器win2003修复,win2003服务器svchost.exe异常
- 苹果手机itunes显示无法连接服务器,苹果手机无法连接到iTunes Store怎么办 连接失败解决方法...
- 程序员必须收藏的网站整理(持续更新)
- python招聘杭州拉勾网_Python爬取拉勾网招聘信息
- 大数据时代带来的伦理问题
- 无需下载 网页版 Matlab
- 【Python】利用Python实现精准三点定位(经纬度坐标与平面坐标转换法求解)
- 网络服务-DCHP原理与配置
热门文章
- 小米wifi每天晚上准时断网_小米 11再次确定,将于28日准时发布,售价更感人
- html ace编辑器,Tiny-editor
- docker 容器安装conposer_docker和php:将依赖项(composer)放入容器中
- linux设备模型的主要功能,Linux设备模型(3)
- html5 电流效果,在HTML5 Canvas 2D上绘制云雾中的电流动画特效
- sql server linux性能,详细了解SQL Server 2008性能和性能优化
- 如何在mysql中添加复选框_如何使用输入和复选框更新mysql
- 计算机上没有office2010,《我安装了office2010,为什么桌面-右键-新建中没有excel呢?》 excel文件找不到...
- 江西小学计算机说课稿,2019江西教师招聘面试-小学数学-说课稿
- axios获取图片显示_Vue.js+axios图片预览以及上传显示进度