effective java 学习笔记_EffectiveJava学习笔记(一)

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

静态工厂方法是返回一个类的实例的静态方法(此处介绍的静态工厂方法并不对应设计模式中的工厂模式),例:基本类型boolean转化为包装类:

public static Boolean valueOf(booleanb) {return b ?Boolean.TRUE : Boolean.FALSE;

}

提供静态工厂方法而不是构造方法的优势:

静态工厂方法有名称,代码易于阅读。构造方法可以重载,但是函数名同类名,无法区分具体实现功能。所以一个类需要多个相同签名的构造器时,应提供静态工厂方法,同时函数名上加以区分。

静态工厂方法不必在每次调用时都创建一个新的对象。

可以返回原类型的任何子类型对象。应用:接口返回对象,同时不使对象的类变成公有的。

返回对象的类可以随着参数不同而改变,只要是已声明返回类型的子类型都是允许的。例:EnumSet没有公有的构造器,只有静态工厂方法,在noneOf静态工厂方法中,判断底层枚举类型的大小,返回不同类型的实例,同时不会影响客户端。

public static > EnumSet noneOf(ClasselementType) {

Enum>[] universe =getUniverse(elementType);if (universe == null)throw new ClassCastException(elementType + " not an enum");if (universe.length <= 64)return new RegularEnumSet<>(elementType, universe);else

return new JumboEnumSet<>(elementType, universe);

}

方法返回对象的所属的类,在编写该静态方法时可以不存在。

静态工厂方法的缺点:

类如果不含有公有的或者受保护的构造器,将不可以被继承。

静态工厂方法难以被发现。常用函数名:from、of、valueOf、instance、create、gatType、newType、type。

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

构建器解决了构造器和静态工厂方法的局限性:当一个类有大量的可选参数时,需要重写多个构造器,代码难以维护。同时也有人提出使用JavaBean的方式(即setParam()),但是这种方式有一个很大的缺陷就是,构造过程被分到了许多调用中,JavaBean可能会处于数据不一致的状态。并且JavaBean模式把类做成不可变的可能性不复存在,需要额外保证它的线程安全。

构造器模式实现:

classNutritionFacts {private final intservingSize;private final intservings;private final intcalories;private final intfat;private final intsodium;private final intcarbohydrate;public static classBuilder {private final intservingSize;private final intservings;private int calories = 0;private int fat = 0;private int sodium = 0;private int carbohydrate = 0;public Builder(int servingSize, intservings) {this.servingSize =servingSize;this.servings =servings;

}public Builder calories(intval) {

calories=val;return this;

}public Builder fat(intval) {

fat=val;return this;

}public Builder sodium(intval) {

sodium=val;return this;

}public Builder carbohydrate(intval) {

carbohydrate=val;return this;

}publicNutritionFacts build() {return new NutritionFacts(this);

}

}privateNutritionFacts(Builder builder) {this.servings =builder.servings;this.calories =builder.calories;this.carbohydrate =builder.carbohydrate;this.fat =builder.fat;this.sodium =builder.sodium;this.servingSize =builder.servingSize;

}

NutritionFacts nutritionFacts= new NutritionFacts.Builder(10,10)

.calories(5)

.carbohydrate(5)

.fat(100)

.sodium(7)

.build();

}

第三条:用私有构造器或者枚举类型强化Singleton属性

Singleton是指仅被实例化一次的类,通常用来代表一个无状态的对象,或本质上唯一的系统组件,实现Singleton的常用方式是将构造器变为私有。如下两种方式:

classSingleton{public static final Singleton INSTANCE = newSingleton();privateSingleton(){ }

}classSingleton2{private static final Singleton2 INSTANCE2 = newSingleton2();privateSingleton2(){ }public staticSingleton2 getInstance(){returnINSTANCE2;

}

}

在方法一中,如果客户端使用setAccessible(true)方法调用私有的构造方法,实例的唯一性将无法保证,此时可以在构造器中判断,如已存在当前类的实例则抛出异常。如下:

public classSingletonDemo {public static void main(String[] args) throwsException {

Singleton singleton1=Singleton.INSTANCE;

Singleton singleton2=Singleton.INSTANCE;

Constructor constructor = Singleton.class.getDeclaredConstructor();

constructor.setAccessible(true);

Singleton singleton3=constructor.newInstance();

System.out.println(singleton1+ "~" + singleton2 + "~" +singleton3);

}

}classSingleton{public static final Singleton INSTANCE = newSingleton();privateSingleton(){if(Objects.nonNull(INSTANCE)){throw new RuntimeException("实例已存在!!");

}

}

}

如果要将Singleton类支持序列化,仅仅实现Serializable接口是不够的,为了保证每次反序列化时不构造一个新的Singleton对象,需要提供readResolve方法。

第三种也是最佳的实现Singleton类的方法是声明一个包含单个元素的枚举类型,这种方式更加简洁,并且提供了序列化机制,避免重复生成实例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值