提防包装类型的 null 值
- public static int testMethod(List<Integer> list) {
- int count = 0;
- for (Integer i : list) {
- count += (i != null) ? i : 0;
- }
- return count;
- }
包装对象和拆箱对象可以自由转换, 这不假, 但是要剔除 null 值, null 值并不能转换为基本类型. 对于此问题, 我们谨记一点: 包装类型参与运算时, 要做 null 值校验.
谨慎包装类型的大小比较
i==j: 在 java 中 "==" 是用来判断两个操作数是否有相等关系的, 如果是基本类型则判断值是否相等, 如果是对象则判断是否是一个对象的两个引用, 也就是地址是否相等, 这里很明显是两个对象, 两个地址不可能相等.
i>j 和 i<j: 在 Java 中,">" 和 "<" 用来判断两个数字类型的大小关系, 注意只能是数字类型的判断, 对于 Integer 包装类型, 是根据其 intValue()方法的返回值 (也就是其相应的基本类型) 进行比较的(其它包装类型是根据相应的 value 值比较的, 如 doubleValue,floatValue 等), 那很显然, 两者不肯能有大小关系的.
优先使用整型池
(1),new 产生的 Integer 对象
new 声明的就是要生成一个新的对象, 没二话, 这是两个对象, 地址肯定不等, 比较结果为 false.
(2), 装箱生成的对象
对于这一点, 首先要说明的是装箱动作是通过 valueOf 方法实现的, 也就是说后两个算法相同的, 那结果肯定也是一样的, 现在问题是: valueOf 是如何生成对象的呢? 我们来阅读以下 Integer.valueOf 的源码:
- public static Integer valueOf(int i) {
- assert IntegerCache.high>= 127;
- if (i>= IntegerCache.low && i <= IntegerCache.high)
- return IntegerCache.cache[i + (-IntegerCache.low)];
- return new Integer(i);
- }
- private static class IntegerCache {
- static final int low = -128;
- static final int high;
- static final Integer cache[];
- static {
- // high value may be configured by property
- int h = 127;
- String integerCacheHighPropValue =
- sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
- if (integerCacheHighPropValue != null) {
- int i = parseInt(integerCacheHighPropValue);
- i = Math.max(i, 127);
- // Maximum array size is Integer.MAX_VALUE
- h = Math.min(i, Integer.MAX_VALUE - (-low));
- }
- high = h;
- cache = new Integer[(high - low) + 1];
- int j = low;
- for(int k = 0; k < cache.length; k++)
- cache[k] = new Integer(j++);
- }
- private IntegerCache() {}
- }
cache 是 IntegerCache 内部类的一个静态数组, 容纳的是 - 128 到 127 之间的 Integer 对象. 通过 valueOf 产生包装对象时, 如果 int 参数在 - 128 到 127 之间, 则直接从整型池中获得对象, 不在该范围内的 int 类型则通过 new 生成包装对象.
不要随便设置随机种子
在 Java 中, 随机数的产生取决于种子, 随机数和种子之间的关系遵从以下两个原则:
种子不同, 产生不同的随机数
种子相同, 即使实例不同也产生相同的随机数
- import java.util.Random;
- public class Client30 {
- public static void main(String[] args) {
- Random r = new Random();
- for(int i=1; i<=4; i++){
- System.out.println("第"+i+"次:"+r.nextInt());
- }
- }
- }
- Random r = new Random(1000);
1000 为随机种子, 运行多次, 虽然实例不同, 但都会获得相同的四个随机数.
在接口中不要存在实现代码
- public class Client31 {
- public static void main(String[] args) {
- // 调用接口的实现
- B.s.doSomeThing();
- }
- }
- // 在接口中存在实现代码
- interface B {
- public static final S s = new S() {
- public void doSomeThing() {
- System.out.println("我在接口中实现了");
- }
- };
- }
- // 被实现的接口
- interface S {
- public void doSomeThing();
- }
在 B 接口中声明了一个静态常量 s, 其值是一个匿名内部类 (Anonymous Inner Class) 的实例对象, 就是该匿名内部类 (当然, 也可以不用匿名, 直接在接口中是实现内部类也是允许的) 实现了 S 接口.
静态变量一定要先声明后赋值
静态变量是在类初始化的时候首先被加载的, JVM 会去查找类中所有的静态声明, 然后分配空间, 注意这时候只是完成了地址空间的分配, 还没有赋值, 之后 JVM 会根据类中静态赋值 (包括静态类赋值和静态块赋值) 的先后顺序来执行. 对于程序来说, 就是先声明了 int 类型的地址空间, 并把地址传递给了 i, 然后按照类的先后顺序执行赋值操作, 首先执行静态块中 i = 100, 接着执行 i = 1, 那最后的结果就是 i =1 了.
不要覆写静态方法
避免在构造函数中初始化其它类
- public class Client35 {
- public static void main(String[] args) {
- Son son = new Son();
- son.doSomething();
- }
- }
- // 父类
- class Father {
- public Father() {
- new Other();
- }
- }
- // 相关类
- class Other {
- public Other() {
- new Son();
- }
- }
- // 子类
- class Son extends Father {
- public void doSomething() {
- System.out.println("Hi, show me Something!");
- }
- }
构造方法循环调用
来源: https://www.cnblogs.com/androidsuperman/p/9358122.html