Effective Java学习笔记一:创建和销毁对象(一)

博客介绍了Java中用静态工厂方法代替构造器的优缺点及常用名称,以Boolean类和单例模式举例说明。还指出静态工厂和构造器在处理大量可选参数时的局限,介绍了重叠构造器、JavaBeans模式和Builder模式,推荐用Builder模式代替多参数构造函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一条:考虑用静态工厂方法代替构造器

静态工厂方法的优点:

1.它们有名称

2.不必在每次调用它们的时候都创建一个新对象(比如单例模式)

3.它们可以返回原返回类型的任何子类型的对象

4.在创建参数化类型实例的时候,它们使代码变得更加简洁

静态工厂方法的缺点:

1.类如果不含公有的或者受保护的构造器,就不能被子类化

2.它们与其他静态方法实际上没有任何区别

 

静态工厂方法常用名称:

valueOf:该方法返回的实例与它的参数具有相同的值,这样的静态工厂方法实际上是类型转换方法

getInstance:返回的实例是通过方法的参数来描述的,对于Singleton来说,该方法没有参数,并返回唯一实例

newInstance:与getInstance类似,但是newInstance能够确保返回的每个实例都与所有其他实例不同

getType:返回对象类型

 

1.以Boolean类为例:

/******源码start******/
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
//Boolean类的静态工厂方法
public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }
/******源码end******/

//使用构造器
Boolean b = new Boolean(true);
//使用静态工厂方法
Boolean b = Boolean.valueOf(true);

2.单例模式

public enum SingleInstance{
    INSTANCE;
    public void fun(){
        //do something
    }
}
SingleInstance.INSTANCE.fun();

创建枚举实例的过程是线程安全的,这种写法功能上与共有域方法相近,但是更简洁,无偿地提供了序列化机制,绝对防止对此实例化,即使实在面对复杂的序列化或者反射攻击的时候。虽然这种方法还没有广泛采用,但是单元素的枚举类型已经成为实现Singleton的最佳方法

普通单例:

public class Singleton{
    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton(){}
    public static final Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

3.设计模式中的基本的原则之一 —— 【里氏替换】原则,就是说子类应该能替换父类

Class Person{
    public static Person getInstance(){
        return new Person();
        //这里可以改为 return new Student()/Teacher() ;
    }
}

Class Student extends Person{}
Class Teacher extends Person{}

4.这条主要是针对带泛型类的繁琐声明而说的,需要重复书写两次泛型参数

Map<String,Object> map = new HashMap<String,Object>();

不过自从 java7 开始,这种方式已经被优化过了 —— 对于一个已知类型的变量进行赋值时,由于泛型参数是可以被推导出,所以可以在创建实例时省略掉泛型参数。

Map<String,Object> map = new HashMap();

第二条:遇到多个构造器参数时要考虑用构造器

静态工厂和构造器都有个共同的局限性:它们不能很好地扩展到大量的可选参数。

此时有三种方法,

一是采用重叠构造器,二是JavaBeans模式,三是Builder模式

package com.chisaki.threadgroup;
/**
 *使用重叠构造器模式
 **/
public class Person {
        //required
	private String name;   
        //optional
	private String age;
        //optional	    
	private String idType;
        //optional
	private String idno;
        //optional    
	private String gender;
        //optional  
	private String adress;  
	
	public Person(String name) {
		this(name,"");
	}
	
	public Person(String name,String age) {
		this(name,age,"");
	}
	
	public Person(String name,String age,String idType) {
		this(name,age,idType,"");
	}
	
	public Person(String name,String age,String idType,String idno) {
		this(name,age,idType,idno,"");
	}
	
	public Person(String name,String age,String idType,String idno,String gender) {
		this(name,age,idType,idno,gender,"");
	}
	
	public Person(String name,String age,String idType,String idno,String gender,String adress) {
		this.name = name;
		this.age = age;
		this.idType = idType;
		this.idno = idno;
		this.gender = gender;
		this.adress = adress;
	}
}

重叠构造器模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且难以阅读

/**
 *使用JavaBeans模式
 */
public class Person {
	private String name;    
	private String age;	    
	private String idType;  
	private String idno;    
	private String gender;  
	private String adress;  	
	public Person() {}
	//setters
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(String age) {
		this.age = age;
	}
	public void setIdType(String idType) {
		this.idType = idType;
	}
	public void setIdno(String idno) {
		this.idno = idno;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public void setAdress(String adress) {
		this.adress = adress;
	}
}

使用JavaBeans模式有很严重的缺点,因为构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的状态,类无法仅仅通过检验构造器参数的有效性来保证一致性。JavaBeans模式阻止了把类做成不可能变的可能,需要付出额外努力来确保他的线程安全。

/**
 *使用Builder模式
 */
package com.chisaki.threadgroup;

public class Person {
	//必要参数
	private String name;    
	private String age;	    
	//可选参数
	private String idType;  
	private String idno;    
	private String gender;  
	private String adress;  	
	
	public static class Builder{
		//必要参数
		private final String name;
		private final String age;
		//可选参数
		private String idType = "";  
		private String idno = "";    
		private String gender = "";  
		private String adress = "";  
		
		public Builder(String name,String age) {this.name = name;this.age = age;}
		
		public Builder idType(String value) {this.idType = value;return this;}
		public Builder idno(String value) {this.idno = value;return this;}
		public Builder gender(String value) {this.gender = value;return this;}
		public Builder adress(String value) {this.adress = value;return this;}
		
		public Person build() {return new Person(this);}
	}
	
	private Person(Builder builder) {
		name = builder.name;
		age = builder.age;
		idType = builder.idType;
		idno = builder.idno;
		gender = builder.gender;
		adress = builder.adress;
	}
}



/**
 *如何使用Builder模式
 */
Person person = new Person.Builder("yui","18")
				.idType("身份证")
				.idno("123456789")
				.gender("M")
				.adress("")
				.build();

容易编写且易于阅读,builder模式模拟了具名的可选参数,可与对参数强加约束条件,builder方法可以检验这些约束条件,将参数从builder拷贝到对象中之后,并在对象域而不是builder域中对它们进行检验。

使用Builder模式来代替多参数构造函数

 

                                                                                                                                       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值