EffectiveJava阅读感想一

1. 遇到多个构造器考虑建造器

多个构造器,只有参数列表不同,应用起来会很不方便,容易混淆,参数过多,调用的时候可能并不知道如此多的参数具体代表什么含义。比如我们可能会有以下的代码片段:

public class Test {
    public Test(String a, int b, boolean c, long d){}
    public Test(int a, int b, boolean c, long d){}
    public Test(int a, String b, boolean c, long d){}
    public Test(float a, double b, int c, long d){}
}

Test类拥有很多构造方法,但是由于构造方法过多导致含义模糊,我们在实例化Test的对象的时候,不知道具体应该调用哪一个构造方法,所以有的时候我们可能会在类中写一个无惨的构造方法,然后这样为Test中的属性赋值:

Test test = new Test() ;
test.setA(a) ;
test.setB(b) ;
test.setC(c) ;
test.setD(d) ;

这样的代码看以来没什么不妥,不过从EffectiveJava书中,这种方式会发生一个问题,JavaBean状态不一致问题,下述讲述。

总之,如果存在多个构造器的时候,需要考虑用Builder模式。构建builder模式,可以保证JavaBean一致性,用户提前设置属性到builder中,然后通过builder来构建Bean实例,由于静态内部类可以产生多个实例,所以多个线程访问会出现多个实例,不会影响当前builder实例的内容,builder对象不受影响,通过builder构造Test也就没有状态不一致的问题了。如下代码:

public class Test {
    private String name ;
    private int age ;
    public Test(TestBuilder builder){
        this.age = builder.age ;
        this.name = builder.name ;
    }
    public static class TestBuilder{
        private String name ;
        private int age ;
        public TestBuilder name(String name){
            this.name = name ;
            return this ;
        }
        public TestBuilder age(int age){
            this.age = age ;
            return this ;
        }
        public Test build(){
            return new Test(this) ;
        }
    }

    public static void main(String[] args) {
        Test test = new TestBuilder().age(11).name("EffectiveJava").build();
    }
}

2.JavaBean状态不一致

个人理解JavaBean状态一致:用户用指定的参数创建JavaBean,创建之后此JavaBean内包含的属性值与用户指定的参数值相同,上述代码中,如果用构造方法创建的对象,是可以保持一致性的,因为程序在执行构造方法之后,才生成新的实例,所以实例中的属性值和用户指定的必定相同,因为在调用构造方法之前根本没有对象产生,用户无法通过一个不存在的对象来操作对象的属性。用set来设置JavaBean的值,不能保持一致性,创建对象后,用户通过set来设置属性值,但是在设置之后,另外的用户可以通过其他线程来调用set方法来更改此属性,此时也就是JavaBean状态不一致。

3.攻击单例模式

单例模式大家都很熟悉,例子我不在举出,只讨论在什么情况下会产生多个实例:

1.反射机制,我们可以通过反射来调用单例类的私有构造方法来创造对象。解决方式:可以再类的私有构造方法中增加判断,第二次创建该对象时候抛出异常。

2.IO流反序列化,利用IO流对类进行反序列化时,会生成新的对象。解决方式:单例类实现readResolve方法。

4. 避免创建不必要的对象

如果变量不需要改变,则声明为常量,不要每次都new一个对象

计算应该用基本数据类型,而不是用封装类。如使用int、long,但要规避使用Integer、Long

 

你可能感兴趣的:(EffectiveJava阅读)