1.Java语言支持四种类型:
引用类型:类(包括Enum)、接口、数组
基本类型
2.方法签名由名称、所有参数类型组成;签名的方法不包含返回类型
一、创建和销毁对象
第1条.用静态工厂方法代替构造器
public static Boolean valueOf(boolean b){
return b ? Boolean.TRUE : Boolean.FALSE;
}
1.静态工厂方法与构造器不同的优势
1).它们有名称。
比如在下面这种情况下,如果我们使用构造函数,在调用构造函数的时候很容易混淆两者。
public class Test {
Test(int i, String s){
}
Test(String s, int i){
}
}
2).不必每次调用它们的时候都创建一个新的对象。
3).它们可以返回原返回类型的任何子类型的对象。
按照惯例,接口Type的静态工厂方法被放在一个名为Types的不可实例化的伴生类中。例如,Java Collections Framework的集合接口中有45个工具实现,分别提供了不可修改的集合、同步集合,等。几乎所有这些实现都通过类java.util.Collections中导出。所有返回对象的类都是非公有的。
4).所返回的对象的类可以随着每次调用的变化而发生变化。(我理解这其实和优点3是一个意思)
5).方法返回的对象所属的类,在编写包含该静态工厂的类时可以不存在。(我理解这还是优点3带来的好处)
2.静态工厂方法与构造器不同的劣势
1).类如果不含公有的或者受保护的构造器,就不能被子类化。
2).很难发现。
第2条.遇到多个构造器参数时要考虑使用构建器
静态工厂和构造器共同的局限性就是:它们都不能很好的扩展到大量的可选参数。
假设我们需要表示营养成分表,其中有几个域是必须的,还有超过20个可选域,通常情况下我们会采用重叠构造器的模式。
package com.example.ownlearn;
import lombok.Data;
@Data
public class Nutrition {
//必填
private final int servingSize;
private final int servings;
//选填
private final int calories;
private final int fat;
public Nutrition(int servingSize,int servings) {
this(servingSize,servings,0,0);
}
public Nutrition(int servingSize, int servings, int calories){
this(servingSize,servings,calories,0);
}
public Nutrition(int servingSize, int servings, int calories, int fat) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
}
}
这种方式可行,但是我们可以看到并没有只给servingSize、servings、fat赋值的构造方法,这意味着我们还是要调用最后一个构造函数,这导致我们需要给某些我们并不想设置的参数传递值,如果我们有大量参数,那么这种方式就会变得不那么好。
我们还有第二种方式,JavaBean模式,我们先调用一个无参的构造器来创建对象,然后再调用setter方法为每个参数赋值。这种方式存在的问题是,因为构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的对象将会导致失败。
第三种方式,建造者模式,既能保证像重叠构造器模式那样的安全性,也能保证像JavaBean那样的可读性。
package com.example.ownlearn;
public class NutritionFact {
//必填
private final int servingSize;
private final int servings;
//选填
private final int calories;
private final int fat;
public static class Builder{
//必填
private final int servingSize;
private final int servings;
//选填
private final int calories = 0;
private final int fat = 0;
public Builder(int servingSize,int servings){
this.servings = servings;
this.servingSize = servingSize;
}
public Builder calories(int calories){
calories = calories;
return this;
}
public Builder fat(int fat){
fat = fat;
return this;
}
public NutritionFact build(){
return new NutritionFact(this);
}
}
public NutritionFact (Builder builder){
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
}
}
我们这样调用
NutritionFact nutritionFact = new NutritionFact.Builder(1,1).fat(1).build();
如果我们的类为父类,我们可以这样来实现。
package com.example.ownlearn;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
public class Pizza {
public enum Topping {HAM,HUSHROOM,ONION,PEPPER,SAUSAGE}
final Set<Topping> toppings;
abstract static class Builder<T extends Builder<T>>{
EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);
public T addTopping(Topping topping){
toppings.add(Objects.requireNonNull(topping));
return self();
}
abstract Pizza build();
protected abstract T self();
}
Pizza(Builder<?>builder){
toppings = builder.toppings.clone();
}
}
package com.example.ownlearn;
public class Calzone extends Pizza {
private final boolean sauceinside;
public static class Builder extends Pizza.Builder<Builder>{
private boolean sauceinside = false;
public Builder sauceInside(){
sauceinside = true;
return this;
}
@Override
Calzone build() {
return new Calzone(this);
}
@Override
protected Builder self() {
return this;
}
}
Calzone(Builder builder) {
super(builder);
this.sauceinside = builder.sauceinside;
}
}
package com.example.ownlearn;
import java.util.Objects;
public class NyPizza extends Pizza {
public enum Size{SMALL}
private final Size size;
public static class Builder extends Pizza.Builder<Builder>{
private final Size size;
public Builder(Size size){
this.size = Objects.requireNonNull(size);
}
@Override
public NyPizza build() {
return new NyPizza(this);
}
@Override
protected Builder self() {
return this;
}
}
NyPizza(Builder builder) {
super(builder);
size = builder.size;
}
}
我们这样调用
NyPizza nyPizza = new NyPizza.Builder(SMALL).addTopping(Pizza.Topping.SAUSAGE).build();
Calzone calzone = new Calzone.Builder().addTopping(Pizza.Topping.HAM).sauceInside().build();