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

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

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

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最大值=2147483647
int limit = 999999999; // 9个9
if (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);

Java日常错误及需要注意细节,持续更新......的更多相关文章

  1. java 学习必备的软件,持续更新中

    小编会持续更新在学习Java过程中需要的软件以及各种文件: 话不多说,看行动! 一:JDK (1)JDK1.8(*64): 链接:https://pan.baidu.com/s/1vM0jNXn2CT ...

  2. Java中的static(1)【持续更新】——关于Eclipse的No enclosing instance of type ... 错误的理解和改正

    No enclosing instance of type SomeClass is accessible. Must qualify the allocation with an enclosing ...

  3. java 超详细面经整理(持续更新)2019.12.19

    目录 Java SE 请你解释HashMap中为什么重写equals还要重写hashcode? 请你介绍一下map的分类和常见的情况 请你讲讲Java里面的final关键字是怎么用的? 请你谈谈关于S ...

  4. java 超详细面经整理(持续更新)2019.12.18

    目录 Java SE 请你谈谈Java中是如何支持正则表达式操作的? 请你简单描述一下正则表达式及其用途. 请你比较一下Java和JavaSciprt? 在Java中如何跳出当前的多重嵌套循环? 讲讲 ...

  5. JAVA常见面试题问题简述(持续更新中)

    JAVA常见面试题问题简述 1. springcloud和dubbo的区别 ①相比之下springcloud 的社区会更加活跃,解决问题的速度也会越来越快,dubbo相对来说如果碰到没有解决的问题,就 ...

  6. Myeclipse中web project各种常见错误及解决方法(持续更新)

    创建web project时的问题 error:Install Dynamic web Module Facet卡住 solution:把网络关掉再创建就可以 Servlet error:The se ...

  7. 【java学习】实践中总结--持续更新中

    目录: 一些定义 配置环境 相关语法 1.一些定义 java中DO的含义: https://blog.csdn.net/canot/article/details/51698047 DAO 中包含了各 ...

  8. 【java】Java相关学习参考链接(持续更新)

    How to do in java,https://howtodoinjava.com/,Java手册,分版本,并且有每个版本的新特性的详细解析. Java World,https://www.jav ...

  9. java常用代码段整理(持续更新)

    FileWriter指定编码格式 FileWriter 默认是用(ISO-8859-1 or US-ASCII)西方编码的,总之不是UTF-8的,而FileWriter类有getEncoding方法, ...

随机推荐

  1. 基于NIO的同步非阻塞编程完整案例,客户端发送请求,服务端获取数据并返回给客户端数据,客户端获取返回数据

    这块还是挺复杂的,挺难理解,但是多练几遍,多看看研究研究其实也就那样,就是一个Selector轮询的过程,这里想要双向通信,客户端和服务端都需要一个Selector,并一直轮询, 直接贴代码: Ser ...

  2. 【codeforces】【比赛题解】#872 CF Round #440 (Div.2)

    链接. [A]寻找漂亮数字 题意: 给定了两列非零数字.我们说一个数是漂亮的,当它的十进制表达中有至少一个数从数列一中取出,至少有一个数从数列二中取出.最小的漂亮数字是多少? 输入: 第一行两个数\( ...

  3. go 函数介绍

    1. 定义:有输入.有输出,用来执行一个指定任务的代码块 func functionname([parametername type]) [returntype] { //function body ...

  4. python 根据输入的内容输出类型

    类型判断 from functools import singledispatch import numbers from collections import abc from collection ...

  5. qt使用动态库(DLL)

    本文主要讲解在QT开发环境中如何使用VC生成的DLL及QT自身生成的DLL.至于其它情况本文不作讨论. 连接库分为2种 (1)动态连接库,通常有.h .lib .dll三个文件,功能实现在dll中 ( ...

  6. Django-模板继承、包含和静态文件配置

    一.模板继承 模板继承可以减少页面内容的重复定义,实现页面内容的重用 典型应用:网站的头部.尾部是一样的,这些内容可以定义在父模板中,子模板不需要重复定义 block标签:在父模板中预留区域,在子模板 ...

  7. 使用的vue、elementUI、vuex、express、mongoDB的单页应用

    基于vue.vuex.express.mongodb的一个单页应用,包括前后端,前端主要是使用vue,后端是node的express,数据库是使用的mongodb 1.下载使用 git clone h ...

  8. android设备休眠

    从上面的连接里面找到了一些资料: 如果一开始就对Android手机的硬件架构有一定的了解,设计出的应用程序通常不会成为待机电池杀手,而要设计出正确的通信机制与通信协议也并不困难.但如果不去了解而盲目设 ...

  9. wpf mvvm模式下的image绑定

    view文件 <Image Grid.Column="2" Width="48" Height="64" Stretch=" ...

  10. 关于Eclipse连接sql server 2008的若干问题

    以下内容转自:https://www.cnblogs.com/skylarzhan/p/7619977.html Eclipse中使用SQL server 2008数据库 一.准备材料 要能够使用数据 ...