编写高质量代码+改善Java程序的151个建议 总结(二)

建议31  在接口中不要存在实现代码
建议32  静态变量一定要先声明后赋值

     这要从静态变量的诞生说起了,静态变量是类加载时被分配到数据区(Data Area)的,它在内存中只有一个拷贝,不会被分配多次,其后的所有赋值操作都是值改变,地址则保持不变。我们知道JVM初始化变量是先声明空间,然后再赋值的,也就是说:

    int i=100;  

    在JVM中是分开执行,等价于:  

    int i;  //分配地址空间  

    i=100;  //赋值 

    静态变量是在类初始化时首先被加载的,JVM会去查找类中所有的静态声明,然后分配空间,注意这时候只是完成了地址空间的分配,还没有赋值,之后JVM会根据类中静态赋值(包括静态类赋值和静态块赋值)的先后顺序来执行。对于程序来说,就是先声明了int类型的地址空间,并把地址传递给了i,然后按照类中的先后顺序执行赋值动作。

建议33  不要覆写静态方法

    见文章 Java-static方法

建议34 构造函数尽量简化

   子类是如何实例化的?子类实例化时,会首先初始化父类(注意这里是初始化,可不是生成父类对象),也就是初始化父类的变量,调用父类的构造函数,然后才会初始化子类的变量,调用子类自己的构造函数,最后生成一个实例对象。

建议35 不要在构造函数中声明初始化其他类
建议36 使用构造代码精炼程序

    在Java中一共有四种类型的代码块:
    (1)普通代码块
    就是在方法后面使用“{}”括起来的代码片段,它不能单独执行,必须通过方法名调用执行。
    (2)静态代码块
    在类中使用static修饰,并使用“{}”括起来的代码片段,用于静态变量的初始化或对象创建前的环境初始化。
    (3)同步代码块
    使用synchronized关键字修饰,并使用“{}”括起来的代码片段,它表示同一时间只能有一个线程进入到该方法块中,是一种多线程保护机制。
    (4)构造代码块

    在类中没有任何的前缀或后缀,并使用“{}”括起来的代码片段。

    构造代码块会在每个构造函数内首先执行(需要注意的是:构造代码块不是在构造函数之前运行的,它依托于构造函数的执行)。例如:

public class Client {  
     {  
         //构造代码块  
         System.out.println("执行构造代码块");  
     }  
 
     public Client(){  
          System.out.println("执行无参构造");  
     }  
 
     public Client(String _str){  
          System.out.println("执行有参构造");  
     }  
}

    等价于:

public class Client {  
     public Client(){  
          System.out.println("执行构造代码块");  
          System.out.println("执行无参构造");  
     }  
 
     public Client(String _str){  
          System.out.println("执行构造代码块");  
          System.out.println("执行有参构造");  
     }  
}

    因此构造代码块应用到如下场景中:

    (1)初始化实例变量(Instance Variable)

    如果每个构造函数都要初始化变量,可以通过构造代码块来实现。当然也可以通过定义一个方法,然后在每个构造函数中调用该方法来实现,没错,可以解决,但是要在每个构造函数中都调用该方法,而这就是其缺点,若采用构造代码块的方式则不用定义和调用,会直接由编译器写入到每个构造函数中,这才是解决此类问题的绝佳方式。

    (2)初始化实例环境

    一个对象必须在适当的场景下才能存在,如果没有适当的场景,则就需要在创建对象时创建此场景,例如在JEE开发中,要产生HTTP Request必须首先建立HTTP Session,在创建HTTP Request时就可以通过构造代码块来检查HTTP Session是否已经存在,不存在则创建之。

建议37 构造代码块会想你所想

    上一个人建议说编译器会把构造代码块插入到每一个构造函数中,但是

    (1)若遇到this关键字(即构造函数调用自身其他构造函数时)则不插入构造代码块,即只执行一次构造代码

    (2)而super方法并没有这个特殊,只是编译器把构造代码块插入super方法之后执行

建议38 使用静态内部类提高封装性
public class Person{  
     //姓名  
     private String name;  
     //家庭  
     private Home home;  
     //构造函数设置属性值  
     public Person(String _name){  
          name = _name;  
     }  
     /* home、name的getter/setter方法省略 */  
 
     public static class Home{  
          //家庭地址  
          private String address;  
          //家庭电话  
          private String tel;  
 
          public Home(String _address,String _tel){  
            address = _address;  
            tel = _tel;  
          }  
          /* address、tel的getter/setter方法省略 */  
     }  
} 
public static void main(String[] args) {  
     //定义张三这个人  
     Person p = new Person("张三");  
     //设置张三的家庭信息  
     p.setHome(new Person.Home("上海","021"));  
} 

         静态内部类的优点:

        (1)提高封装性。从代码位置上来讲,静态内部类放置在外部类内,其代码层意义就是:静态内部类是外部类的子行为或子属性,两者直接保持着一定的关系。
        (2)提高代码的可读性。相关联的代码放在一起,可读性当然提高了。
        (3)形似内部,神似外部。静态内部类虽然存在于外部类内,而且编译后的类文件名也包含外部类(格式是:外部类+$+内部类),但是它可以脱离外部类存在,也就是说我们仍然可以通过new Home()声明一个Home对象,只是需要导入“Person.Home”而已。

        静态内部类与普通内部类的区别如下:

    (1)静态内部类不持有外部类的引用

        在普通内部类中,我们可以直接访问外部类的属性、方法,即使是private类型也可以访问,这是因为内部类持有一个外部类的引用,可以自由访问。而静态内部类,则只可以访问外部类的静态方法和静态属性(如果是private权限也能访问,这是由其代码位置所决定的),其他则不能访问。

    (2)静态内部类不依赖外部类

        普通内部类与外部类之间是相互依赖的关系,内部类实例不能脱离外部类实例,也就是说它们会同生同死,一起声明,一起被垃圾回收器回收。而静态内部类是可以独立存在的,即使外部类消亡了,静态内部类还是可以存在的。

    (3)普通内部类不能声明static的方法和变量

        普通内部类不能声明static的方法和变量,注意这里说的是变量,常量(也就是final static修饰的属性)还是可以的,而静态内部类形似外部类,没有任何限制。

建议39 使用匿名类的构造函数
List l2 = new ArrayList(){{}}; 
    类似于:
//定义一个继承ArrayList的内部类  
class Sub extends ArrayList{  
     {  
        //初始化块  
     }  
}  
//声明和赋值  
List l3 = new Sub(); 

       因为匿名类没有名字,初始化块就是它的构造函数。当然,一个类中的构造函数块可以没有,也可以是多个,也就是说可以出现如下代码:

List l1 = new ArrayList(){}; 
List l2 = new ArrayList(){{}}; 
List l3 = new ArrayList(){{}{}{}{}{}}; 
建议40 匿名类的构造函数很特殊

    一般类(也就是具有显式名字的类)的所有构造函数默认都是调用父类的无参构造,而匿名类在初始化时直接调用父类的同参数构造,然后再调用自己的代码块。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值