1、【强制】所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。
说明: 对于 Integer var=?在-128 至 127 之间的赋值, Integer 对象是在
IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生
,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。
示例如下:
package java基础.类初始化问题;
/**
* @Author: wangxi
* @Description :
* @Date: 2018/5/30 0030 20:02
*/
public class Demo03 {
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
// 下面返回false,参考上述的第一条规范讲解
System.out.println(e == f); // false
Long g = 3L;
System.out.println(a.intValue()); // 1
System.out.println(c == d); // true
System.out.println(c == (a + b)); //true
// 所有包装类重写了equals方法。首先用了instanceof判断。
System.out.println(c.equals(a + b)); //true
System.out.println(g == (a + b)); //true自动拆箱,然后隐式强转
System.out.println(g.equals(a + b)); //false
int tem1 = 1;
long temp2 = 1L;
System.out.println(tem1 == temp2); // true
/** 反编译后的代码
* public static void main(String args[])
{ // 返回Integer对象。注意上述的坑
Integer a = Integer.valueOf(1);
Integer b = Integer.valueOf(2);
Integer c = Integer.valueOf(3);
Integer d = Integer.valueOf(3);
Integer e = Integer.valueOf(321);
Integer f = Integer.valueOf(321);
Long g = Long.valueOf(3L);
System.out.println(a.intValue());
System.out.println(c == d);
System.out.println(c.intValue() == a.intValue() + b.intValue());
System.out.println(c.equals(Integer.valueOf(a.intValue() + b.intValue())));
System.out.println(g.longValue() == (long)(a.intValue() + b.intValue()));
System.out.println(g.equals(Integer.valueOf(a.intValue() + b.intValue())));
}
*/
}
}
笔者使用了jad反编译工具非常好用。需要的小伙伴可以留言哟!
2、【推荐】循环体内,字符串的联接方式,使用 StringBuilder 的 append 方法进行扩展。
反例:
String str = “start”;
for(int i=0; i<100; i++){
str = str + “hello”;
}
说明: 反编译出的字节码文件显示每次循环
都会 new 出一个 StringBuilder 对象,然后进行append 操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费。这样会创建很多StringBuilder对象
。
3、【推荐】使用 entrySet 遍历 Map 类集合 KV,而不是 keySet 方式进行遍历。
keySet 其实是遍历了 2 次,而entrySet 只遍历了一次,效率更高。
package 集合底层源码分析;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: wangxi
* @Description :
* @Date: 2018/8/15 0015 9:54
*/
public class Map的遍历 {
public static void main(String[] args) {
// 为了优化考虑,在创建ArrayList、HashMap时,指定大小。
// 扩容元素的复制很消耗资源!
Map<Integer, Integer> map = new HashMap<>();
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
// 方法一:
for (Map.Entry<Integer, Integer> m : map.entrySet()) {
System.out.println(m);
}
System.out.println("=====================================");
// 方法二 JDK1.8的方法
map.forEach((K, V) -> System.out.println(K + ":" + V));
}
}
内容扩展:foreach的实现原理:
public class Iterable_eros {
List<String> strings;
public void display(){
for(String s : strings){
System.out.println(s);
}
}
}
经过反编译后的代码如下:
public void display (){
line0 : aload_0
getfield java.util.List my.lang.Iterable_eros.strings
invokeinterface java.util.Iterator java.util.List.iterator() 1
astore_2
goto line30
line13 : aload_2
invokeinterface java.lang.Object java.util.Iterator.next() 1
checkcast java.lang.String
astore_1
line23 : getstatic java.io.PrintStream java.lang.System.out
aload_1
line27 : invokevirtual void java.io.PrintStream.println(java.lang.String)
line30 : aload_2
invokeinterface boolean java.util.Iterator.hasNext() 1
ifne line13
line39 : return
可以看到,foreach语法最终被编译器转为了对Iterator.next()的调用
。而作为使用者的我们, jdk并没用向我们暴露这些细节,我们甚至不需要知道Iterator的存在,认识到jdk的强大之处了吧。
4、【推荐】高度注意 Map 类集合 K/V 能不能存储 null 值的情况,如下表格:
集合类 | Key | Value | Super | 说明 |
---|---|---|---|---|
Hashtable | 不允许为null | 不允许为null | Dictionary | 线程安全 |
ConcurrentHashMap | 不允许为 null | 不允许为 null | AbstractMap | 分段锁技术 |
TreeMap | 不允许为 null | 不允许为 null | AbstractMap | 线程不安全 |
HashMap | 允许为 null(只有一个null键) | 允许为 null(有多个null值) | AbstractMap | 线程不安全 |
反例: 由于 HashMap 的干扰,很多人认为 ConcurrentHashMap 是可以置入 null 值,注意存储null 值时会抛出 NPE 异常。
继续更新中……