Effective Java 阅读日记 1()

  本篇文章为你整理了Effective Java 阅读日记 1()的详细内容,包含有 Effective Java 阅读日记 1,希望能帮助你了解 Effective Java 阅读日记 1。

  在方法内部添加一个静态方法,用于获取一个对象,代替构造器的功能;

  比如,在boolean包装Boolean类中,就有valueOf方法可以代替构造方法获得一个Boolean对象;

  

public static Boolean valueOf(boolean b) {

 

   return (b ? TRUE : FALSE);

  

 

  
如Boolean类:Boolean类加载结束后,默认会创建两个Boolean对象,分别表示true和false,在使用静态工厂创建对象时,直接将代表true或false的对象返回,以节约内存使用和程序效率。

  

public final class Boolean implements java.io.Serializable,

 

   Comparable Boolean

   //默认创建两个Boolean对象,用于表示TRUE和FALSE

   public static final Boolean TRUE = new Boolean(true);

   public static final Boolean FALSE = new Boolean(false);

   // 包装了boolean类,这里存值

   private final boolean value;

   // 构造方法新创建了一个Boolean对象

   public Boolean(boolean value) {

   this.value = value;

   //使用valueOf方法,直接返回Boolean类加载时创建的两个静态对象,无需再次创建对象。

   public static Boolean valueOf(boolean b) {return (b ? TRUE : FALSE);}

   public static Boolean valueOf(String s) {

   return parseBoolean(s) ? TRUE : FALSE;

  

 

  
静态方法可以返回对象,而无需将对象的类设为公有的;

  静态方法可以通过接口返回不同的对象。EnumSet没有构造器,只能通过静态工厂创建对象,在OpenJDK实现中,EnmuSet的实现有两种类型:RegalarEumSet和JumboEnumSet;当枚举元素数量等于小于64时,静态工厂方法返回RegalarEumSet对象;当枚举元素数量大于64时,静态工厂方法返回JumboEnumSet对象。(对于调用者,无需知道背后的实现原理,直接使用就好;对于EnumSet开发者,此做法用于代码优化。)

  
//静态工厂方法需要在API中寻找,没有构造方法方便

   public static Apple getNewApple(){return new Apple("redApple","fresh");}

  

 

 

  
valueOf,也是类型转换;

  createInstance或getInstance,通过参数获取一个对象,参数可以与成员变量不同;

  createInstance或netInstance,保证每次返回一个新创建的实例;

  getInstance一般用在单例模式。

  
有些参数有些时候不需要输入,但构造器中必须填入一个值;

  JavaBeans模式,即一堆setter方法,这样可以解决上面的问题,但JavaBeans模式有严重的缺点,在构造过程中JavaBean可能处于不一致状态,即线程不安全。

  这个时候,就可以考虑使用建造者Builder模式

  

public class 建造者模式 {

 

   public static void main(String[] args) {

   Cat cat = new Cat.Builder("小黑")

   .age(12).color("White").build();

   System.out.println(cat);

  class Cat{

   private String name;

   private int age;

   private String color;

   private String owner;

   public static class Builder{

   //必要参数

   private String name;

   //可选参数

   private int age;

   private String color;

   private String owner;

   public Builder(String name) {this.name = name;}

   public Builder age(int val){age=val;return this;}

   public Builder color(String val){color=val;return this;}

   public Builder owner(String val){owner=val;return this;}

   public Cat build(){return new Cat(this);}

   public Cat(Builder builder) {

   owner = builder.owner;

   color = builder.color;

   age = builder.age;

   name = builder.name;

  // toString

  

 

  Builder模拟了具有名字的可选参数,这样的客户端易于编写,易于阅读;

  代码

  

//这里先创建一个抽象类FriedRice

 

  //然后分别创建两个类继承FriedRice,分别为FriedRiceWithHam和FriedRiceWithEgg

  //fried rice 炒饭 可以添加 老干妈LaoGanMa、辣条LaTiao、再加一个鸡蛋Egg等

  // ham 火腿 egg鸡蛋

  //FriedRiceWithHam 火腿炒饭,可以有:大、中、小 三种 LARGE MEDIUM SMALL

  //FriedRiceWithEgg 蛋炒饭,spicy辣度 可以选择:little微辣 general中辣 very特辣

  //具体开发中不要使用中文,也不要使用拼音

  //先整一个抽象类FriedRice

  abstract class FriedRice{

   //额外要加的东西

   public enum Ingredient{老干妈,辣条,Egg}//实际开发不要使用中文

   private Set Ingredient ingredientSet;

   abstract static class Builder T extends Builder T {

   EnumSet Ingredient ingredients = EnumSet.noneOf(Ingredient.class);//默认没有配料

   public T addIngredient(Ingredient val){ingredients.add(val);return self();}//添加配料

   public abstract FriedRice build();

   protected abstract T self();

   FriedRice(Builder ? builder){

   ingredientSet = builder.ingredients.clone();

  //创建一个FriedRiceWithHam火腿炒饭

  @ToString(callSuper = true)//是Lombok插件的注解,可以自动生成toString方法,文章主要讲解内容不包含这部分,忽略就好

  class FriedRiceWithHam extends FriedRice{

   public enum Size{SMALL,MEDIUM,LARGE}

   private Size size;//大小

   public static class Builder extends FriedRice.Builder Builder {

   private Size size;

   public Builder(Size size){this.size = size;}

   @Override public FriedRice build() {return new FriedRiceWithHam(this);}

   @Override protected Builder self() {return this;}

   FriedRiceWithHam(Builder builder) {

   super(builder);

   this.size = builder.size;

  //创建一个FriedRiceWithEgg鸡蛋炒饭

  @ToString(callSuper = true)//是Lombok插件的注解,可以自动生成toString方法,文章主要讲解内容不包含这部分,忽略就好

  class FriedRiceWithEgg extends FriedRice{

   public enum Spicy{LITTLE,GENERAL,VERY}

   private Spicy spicy;

   public static class Builder extends FriedRice.Builder Builder {

   private Spicy spicy;

   public Builder(Spicy spicy){this.spicy = spicy;}

   @Override public FriedRice build() {return new FriedRiceWithEgg(this);}

   @Override protected Builder self() {return this;}

   FriedRiceWithEgg(Builder builder) {

   super(builder);

   spicy = builder.spicy;

  

 

  使用

  

public class Builder模式也适用于类层次结构 {

 

   public static void main(String[] args) {

   //创建一个鸡蛋炒饭,中辣,添加老干妈

   FriedRice friedRiceWithEgg = new FriedRiceWithEgg.Builder(FriedRiceWithEgg.Spicy.GENERAL)

   .addIngredient(FriedRice.Ingredient.老干妈).build();

   //创建一个火腿炒饭,大份,添加鸡蛋

   FriedRice friedRiceWithHam = new FriedRiceWithHam.Builder(FriedRiceWithHam.Size.LARGE)

   .addIngredient(FriedRice.Ingredient.Egg).build();

  

 

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

  Singleton,即单例模式;对于一个类,只会被实例化一次,后续通过静态方法获取对象也只能获取到这一个对象,不会再次创建新的对象。

  创建一个Singleton,有两种方式

  私有构造器

  将构造器私有化,然后通过getInstance方法创建并获取对象。

  默认情况下,可以通过以下方式实现单例模式。

  

//Chopsticks n.筷子

 

  //这里假定筷子只能有一根

  //这里创建一个单例对象

  class Chopstick{

   private static final Chopstick INSTANCE = new Chopstick();//类加载后,自动创建一个Chopstick对象,

   private Chopstick(){}//构造器私有化,禁止二次创建

   public static Chopstick getInstance(){return INSTANCE;}//获取实例

  

 

  但是,这个单例是可以通过反射进行破坏;

  

public static void main(String[] args) throws Exception {

 

   Chopstick instance = Chopstick.getInstance();//第一个实例对象

   //第二个实例对象

   Class ? aClass = Class.forName("com.yn.study.chapter1.Chopstick");//获取Class对象

   Constructor ? declaredConstructor = aClass.getDeclaredConstructor();//获取Constru对象

   declaredConstructor.setAccessible(true);//跳过private检查

   Chopstick chopstick = (Chopstick) declaredConstructor.newInstance();//创建实例对象

   System.out.println(instance);

   System.out.println(chopstick);

   /**输出结果如下:

   * com.yn.study.chapter1.Chopstick@7f31245a

   * com.yn.study.chapter1.Chopstick@6d6f6e28

   * 表示这两个对象不是同一个对象

  

 

  所以,可以在构造方法里面添加判断,让第二次创建过程抛出错误来解决破坏;

  

class Chopstick{

 

   private static final Chopstick INSTANCE = new Chopstick();//类加载后,自动创建一个Chopstick对象,

   private Chopstick() {if (INSTANCE!=null)throw new Error("请不要二次创建对象");}//构造器私有化,禁止二次创建

   public static Chopstick getInstance(){return INSTANCE;}//获取实例

  

 

  如果要使对象变得可序列化,必须声明readResolve方法

  如果要使对象变得可序列化,仅仅在声明中加上implements Serializable是不够的,为了维护Singleton,必须声明所有实例域是transient(瞬时)的,并声明readResolve方法;

  否则,每当反序列化一个对象,都会创建一个新的对象;

  

public static void main(String[] args) throws Exception {

 

   //单例破解方案——序列化:将对象存储于文件中,然后从文件中读取

   //创建一个单例对象

   Chopstick chopstick1 = Chopstick.getInstance();

   //将对象写入文件

   File file = new File("Chopstick.dat");

   FileOutputStream os = new FileOutputStream(file);

   ObjectOutputStream oos = new ObjectOutputStream(os);

   oos.writeObject(chopstick1);

   oos.close();os.close();

   //将对象从文件中读取

   FileInputStream is = new FileInputStream(file);

   ObjectInputStream ois = new ObjectInputStream(is);

   Chopstick chopstick2 = (Chopstick) ois.readObject();//第二个实例化对象

   System.out.println(chopstick1);

   System.out.println(chopstick2);

   * 输出结果

   * com.yn.study.chapter1.Chopstick@2503dbd3

   * com.yn.study.chapter1.Chopstick@7ef20235

   * 表示这两个对象不是一个对象

  

 

  声明readResolve方法

  

private Object readResolve(){return INSTANCE;}

 

  

 

  这样,上面的结果获得的将是同一个对象。

  

com.yn.study.chapter1.Chopstick@2503dbd3

 

  com.yn.study.chapter1.Chopstick@2503dbd3

  

 

  

//Chopsticks n.筷子

 

  //这里假定筷子只能有一根

  //这里创建一个单例对象

  class Chopstick implements Serializable {

   private static final Chopstick INSTANCE = new Chopstick();//类加载后,自动创建一个Chopstick对象,

   private Chopstick() {if (INSTANCE!=null)throw new Error("请不要二次创建对象");}//构造器私有化,禁止二次创建

   public static Chopstick getInstance(){return INSTANCE;}//获取实例

   private Object readResolve(){return INSTANCE;}//写readResolve方法,防止反序列化破坏单例

  

 

  枚举本就是一个单例对象,而且不可破坏。

  

enum ChopstickPlus{

 

   INSTANCE;

   ChopstickPlus getInstance(){return INSTANCE;}

  

 

  4. 通过私有构造器,使得类不可实例化

  有些类只包含静态方法或静态域,这样的类不希望会被实例化,因为这些类被实例化是没有意义的;

  这里我表示疑惑:应该一般情况下没有人会去尝试实例化一个只有静态方法的类,嗯..但是...,书上说有一些时候会无意识的初始化该类??下面继续记笔记。

  对于没有特别声明构造器的类,其构造器默认是public的,

  
public static long sum(long a,long b){return a+b;}//一个求和的静态方法

   //不希望不必要的工具类实例化

   private EasyMath(){throw new AssertionError();}

  

 

 

  但这样有个缺点:这个类不能有父类。

  5. 优先考虑依赖注入引用资源

  这里..就只写个标题吧。。

  详见Effective Java 第三版 P16页。

  以上就是Effective Java 阅读日记 1()的详细内容,想要了解更多 Effective Java 阅读日记 1的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: