《编写高质量代码—改善java程序的151个建议》知识整理一

1、用偶判断,不用奇判断

     案例:在代码i%2==1?"奇数":"偶数" (java中的求余算法相当于:divided-divided/divisor*divisor)中,当被除数i为-1时,结果是偶数,判断失误,所以该程序应改为:i%2==0?"偶数":"奇数"

2、不要让类型默默转化

    案例:代码long d=lg*60*8,当整型的lg参数和另外两个参数相乘超出整型边界的时候就会变成负数,在转换为long型,结果还是负值

                所以代码需要改为:long d=lg*60*8*1l;

3、在接口中不要存在实现代码

public class Client {
    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();
}

虽然成功打印出了结果。但是如果把实现代码写到接口中,那接口就绑定了可能变化的因素,这就会导致实现不再稳定和可靠,是随时都可能被抛弃、呗更改、被重构的。所以接口中虽然可以有实现,但应该避免使用。

4、静态变量一定要先声明后赋值

代码:

public class demo2 {
    
    static{
        i=100;
    }
    public static int i=1;
    public static void main(String[] args) {
        System.out.println(i);
    }
    
}
public class demo2 {
    public static int i=1;
    static{
        i=100;
    }
    //public static int i=1;
    public static void main(String[] args) {
        System.out.println(i);
    }
    
}

       两段代码的输出结果分别为:1和100,两段代码都能编译,都有结果,值却不一样,这是什么原因呢?我们知道静态变量是类加载时被分配到数据区(Date Area)的,它在内存中只有一个拷贝,它以后的所有操作都是只改变值而不改变地址,而jvm是先声明再赋值,例如:int i=100;等价于int i;//分配地址  i=100//赋值,所以在类初始化的时候,jvm会查找类中的所有静态声明进行加载,然后分配空间。所以向上面这种情况,只是完成了地址空间的分配,而没有赋值,之后jvm就会按照先后顺序来进行复制,所以第二段代码到最后输出的结果为1也就不足为奇了。

5、不要覆写(Override)静态方法,可以隐藏

    代码:

public class Baseextend {
    public static void doSomething(){
        System.out.println("我是父类静态方法");
    }
    public void doAnything(){
        System.out.println("我是父类非静态方法");
    }
}

public class Subextend extends Baseextend{

    public static void doSomething(){
        System.out.println("我是子类静态方法");
    }
    public void doAnything(){
        System.out.println("我是子类非静态方法");
    }
}

public class Extendtext {
    @SuppressWarnings("static-access")
    public static void main(String[] args) {
          Baseextend base=new Subextend();
          base.doSomething();
          base.doAnything();
          

    }
}

      上面的输出结果为:我是父类静态方法        我是子类非静态方法

      分析原因:我们知道一个实例对象有两个类型:表面类型(Apparent Type)和实际类型(Actual Type),表面类型是声明时的类型,实际类型是对象产生时的类型。比如例子base的表面类型是Baseextend,实际类型是Subextend。对于非静态方法,它是根据对象的实际类型来执行的,对于静态方法,如果采用类实例(对象)的方法来访问,jvm则会通过对象的表面类型来访问对应的静态方法,所以出现上面的结果也就不足为奇了。

世上无难事,只怕有心人
原文地址:https://www.cnblogs.com/shewu/p/5412884.html