Effective Java学习笔记--创建和销毁对象
创建和销毁对象
一.静态工厂方法代替构造器
静态工厂方法的优缺点
优点:
1.可以自定义名称(可以将功能表述的更加清晰)
2.不必每次调用都创建新的对象(同一对象重复使用)
3.返回的类型可以是原返回类型的任何子类型对象
4.简化创建对象时的代码
缺点:
1.如果不含有公开的构造器,就不能被子类化
2.和普通的静态方法没有区别
二.遇到多个构造器参数时考虑用构建器
如果我们现在需要编写一个描述客户信息的类,在客户的信息中名字是一定有的,其他的信息都是可能用,我们使用三种方法去完成:
1.重叠构造器方法(代码已经简化)
1 /** 2 * 客户信息 3 */ 4 public class Customer { 5 private String name;//姓名 6 private String profession;//职业 7 private int age;//年龄 8 private String gender;//性别 9 10 public Customer(String name){ 11 this.name=name; 12 } 13 14 public Customer(String name,String profession){ 15 this.name=name; 16 this.profession=profession; 17 } 18 19 public Customer(String name,String profession,int age){ 20 this.name=name; 21 this.profession=profession; 22 this.age=age; 23 } 24 25 public Customer(String name,String profession,int age,String gender){ 26 this.name=name; 27 this.profession=profession; 28 this.age=age; 29 this.gender=gender; 30 } 31 }
创建实例:
Customer customer=new Customer("李雷", "程序员", 27, "男");
总结:这里是简化后的代码,此实例才4个参数就如此繁琐,随着参数的增加,将会失去控制。
2.JavaBean模式(调用无参构造方法,然后用set方法赋值)
1 /** 2 * 客户信息 3 */ 4 public class customer { 5 private String name;//姓名 6 private String profession;//职业 7 private int age;//年龄 8 private String gender;//性别 9 10 public customer(){} 11 12 public void setName(String name) { 13 this.name = name; 14 } 15 16 public void setProfession(String profession) { 17 this.profession = profession; 18 } 19 20 public void setAge(int age) { 21 this.age = age; 22 } 23 24 public void setGender(String gender) { 25 this.gender = gender; 26 } 27 }
创建实例:
customer customer=new customer(); customer.setAge(27); customer.setGender("男"); customer.setName("李雷"); customer.setProfession("程序员");
总结:创建实例容易,也比较容易阅读,但是由于对象的构造过程被分到了几部调用中,JavaBean可能处于不一致的状态,而且使用此模式无法将类制作成不可变的。
3.构建器(Builder模式)
1 /** 2 * 客户信息 3 */ 4 public class Customer { 5 private final String name;//姓名 6 private final String profession;//职业 7 private final int age;//年龄 8 private final String gender;//性别 9 10 public static class Builder{ 11 private final String name; 12 13 private String profession="无"; 14 private int age=0; 15 private String gender="未知"; 16 17 public Builder(String name){ 18 this.name=name; 19 } 20 21 public Builder profession(String val){ 22 profession=val; 23 return this; 24 } 25 26 public Builder age(int val){ 27 age=val; 28 return this; 29 } 30 31 public Builder gender(String val){ 32 gender=val; 33 return this; 34 } 35 36 public Customer build(){ 37 return new Customer(this); 38 } 39 } 40 41 private Customer(Builder builder){ 42 name=builder.name; 43 profession=builder.profession; 44 age=builder.age; 45 gender=builder.gender; 46 } 47 }
创建实例:
创建对象时,类名后面加括号表示调用无参的构造函数;不加括号表示调用默认的构造函数或唯一的构造函数
Customer customer=new Customer.Builder("李雷").age(27).gender("男").profession("程序员").build();
总结:编写容易,易于阅读,而且模拟了具名的可选参数,安全性高,后期的扩展性强。
3.单元素枚举是实现Singleton的最佳方法
1 public enum Elvis { 2 INSTANCE; 3 4 public void leaveTheBuilding(){ 5 System.out.println("Singleton!"); 6 } 7 }
创建实例:
Elvis elvis=Elvis.INSTANCE;
4.消除对其对象的引用
下面是一个栈的简单实现:
public class Stack { private Object[] elements; private int size=0; private static final int DEFAULE_INITAL_CAPACITY=16; public Stack(){ elements=new Object[DEFAULE_INITAL_CAPACITY]; } public void push(Object e){ ensureCapacity(); elements[size++]=e; } public Object pop(){ if (size==0) { throw new EmptyStackException(); } return elements[--size]; } public void ensureCapacity(){ if (elements.length==size) { elements=Arrays.copyOf(elements, 2*size+1); } } }
如果一个栈显示增长,然后再收缩,那么从栈中弹出的对象将不会被当做垃圾回收,我们应该将过期的引用清空,将pop方法改动如下:
public Object pop(){ if (size==0) { throw new EmptyStackException(); } elements[size]=null; return elements[--size]; }