【JAVA】 Effective JAVA 学习笔记

https://www.cnblogs.com/yulinfeng/archive/2017/08/03/7282649.html

================================================================================

2.创建和销毁对象

2.1 静态工厂方法代替构造器

2.2 多个构造器参数时用构造器

如下例子:

一个类的构造方法需要多个形参,但是其中某些形参可选可不选:

方案1:重叠构造器:

public class Example {
    public final int A;
    public final int B;
    public final int C;
    public final int D;
   
    public Example (int a , int b){
        this.Example (a,b,0)
    }

    public Example (int a , int b , int c){
        this.Example (a,b,c,0)
    }

    public Example (int a , int b , int c , int d ){
        A =a;
        B =b;
        C =c;
        D =d;
    }
}

缺点:缺少的形参是估计倒数几个,不可有中间缺少形参情形;

方案2:JAVA BEANS:

public class Example {
    public final int A;
    public final int B;
    public final int C;
    public final int D;

    public Example {}
   
    public void setA(int val) {
        A = val;
    }

    public void setB(int val) { ... }

    public void setC(int val) { ... }

    public void setD(int val) { ... }
}

缺点: 多线程下,不同线程对同一个实参的实例化可能导致不一致状态出现

方案3:Builder 模式:

public class Example {
    // 都是private
    private final int A;
    private final int B;
    private final int C;
    private final int D;

    public static class Builder {

        //Example 类必须的构造参数:
        private final int A ;
        private final int B ;

        //Example 类可选的构造参数:
        private final int C = 0 ;
        private final int D = 0 ;

        public Builder (int a , int b) {
            A = a;
            B = b;
        }
        
        public Builder setC(int c) {
            C = c;
            return this;
        }

        public Builder setD(int d) {
            D = d;
            return this;
        }
  
        public Example build() {
            return new Example(this);
        }
    }

    public Example (Builder builder) {
        A = builder.A;
        B = builder.B;
        C = builder.C;
        D = builder.D;
    }
}

初始化的例子:

Example ex = new Example.Builder(100,200).setC(300).setD(400).build();

1.(核心): 在目标类中创建 一个内部静态类---> 通过确保 目标类的初始化完全依赖于其内部静态类,确保多线程安全

2.目标类的成员变量为private 域,内部静态类的成员变量为private 域,但是setC 为public 域---->确保 目标类的初始化完全依赖内部类;

3.内部静态类 的setC() 方法返回不是void 而是目标类 的类型,确保可以连续使用 setC().setD().setE().setD() ,一次性完成成员变量的初始化;

以下方法貌似也可以... ...

没有builder 显的不那么灵活

public static class Example {

    private int A ;
	private int B ;
	
	private int C = 0;
	private int D = 0;
	
	public Example (int a , int b) {
	    A = a;
		B = b;
	}
	
	public Example setC (int c) {
	    C = c;
		return this;
	}
	
	public Example setD (int d) {
	    D = d;
		return this;
	}
}


Example ex = new Example(100,200).setC(300).setD(400);

2.3 用私有构造器或者枚举类型强化Singleton属性

2.4 通过私有构造器强化不可实例化能力

public static class Example {

    ... ...

	private Example (int a , int b) {
        ... ...
	}

}

构造函数为private 域,在初始化Example 是不能通过其构造函数直接初始化,确保此类不可实例化

2.5 避免创建不必要的对象

案例1:

public class Example {

    private final int Date;

    public Example();

    public boolean isBaby {
        Calender cal = Calender.getInstance(...);
        return cal.isBaby(Date);
    } 
}

每次调用Example.isBaby 都会new 一个Calender对象

优化:

public class Example {

    private final int Date;
    private Builder build;
    
    private static class Builder {
        public Calender cal;
        public Builder () {
            cal = Calender.getInstance(...);
        }
    }   
 
    public Example (int val) {
        Date = val;
        build = new Builder();
    }

    public boolean isBaby() {
        return build.cal.isBaby(Date);
    } 
}

///////////////////或者/////////////////

public class Example {

   private final int Date;

   public static Calender cal;

   public Example (int date) {
       Date = date;
       // cal 是static 修饰的,第一次会初始化,后面的实例中直接共享第一次初始化的内存,不会再运行Calender.getInstance() 方法。
       cal = Calender.getInstance(...);
   }

   public boolean isBaby () {
       return cal.isBaby();
   }

}


public class Example {

   private final int Date;

   public Calender cal;

   public Example (int date) {
       Date = date;
       cal = Calender.getInstance(...);
   }

   public boolean isBaby () {
       return cal.isBaby(Date);
   }

}

////////////////////////////////////////////
public class Example {

   private final int Date;

   public Calender cal;

   public Example (int date) {
       Date = date;
   }

   public static boolean isBaby () {
       cal = Calender.getInstance(...);
       return cal.isBaby(Date);
   }
}


boolean IsBaby = Example(19900101).isBaby();//////???????

2.6 消除过期的对象引用

2.7 避免使用终结方法

 

3. 对所以对象都通用的方法

3.1 覆盖equals 时请遵守通用约定

equals方法实现了等价关系:

1.自反性: 对于任何非null的引用值x,x.equals(x) 必须返回true;

2.对称性:对于任何非null的引用值x,y 当且仅当 y.equals(x) 返回true时,x.equals(y)必须返回true;

3.传递性:对于任何非null的引用值x,y,z 如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)也为true;

4.一致性:对于任何非null的引用值x,y 只要equals 的笔记操作在对象中所用的信息没有被修改,多次调用x.equals(y) 就会一直返回true/false;

5.对于任何非null引用值,x.equals(null)必须返回false;

以下是高质量使用equals 的诀窍:

1.使用“==” 操作符检查                        “参数是否为这个对象的引用”

2.使用instanceof 操作符检查             “参数是否为正确的类型”

3.把参数转换成正确的类型;

4.对于该类中的每个“关键”域,检查参数中的域是否与该对象中对应的域相匹配。

 

对于 不是float / double 类型的基本类型域, 用“==”比较

对应 对象引用域,可以递归滴调用equals方法;

对于float域,可以使用Float.compare 方法

对于double域,则使用Double.compare

 

3.2 覆盖equals时总要覆盖hashCode

3.3 始终要覆盖toString

3.4 谨慎覆盖clone

3.5 考虑实现Compareable接口

 

4.类和接口

 

4.1 使类和成员的可访问性最小化

4.2 在公有类中使用访问方法而非公有域

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章