• 创建对象和销毁对象


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

      静态工厂方法:只是一个返回类实例的静态方法。

    例:

      public static Boolean valueOf(boolean b){

        return b ? Boolean.TRUE : Boolean.FALSE;

      }

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

      1.静态工厂方法与构造器不同的第一大优势在于,它们有名称。(避免了多个构造器带来的参数过多,不方便记忆和使用)

      2.静态工厂方法与构造器不同的第二大优势在于,不必在每次调用它们的时候都创建一个新对象。(例如:单例)

      例:Boolean.valueOf(boolean);

      实例受控的类:原因:确保唯一或不可实例化。

      3.静态工厂方法与构造器不同的第三大优势在于,它们可以返回原返回类型的任何子类类型的对象。

      4.静态工厂方法与构造器不同的第四大优势在于,在创建参数化类型实例的时候,它们使代码变得更加简洁。

      复杂的:Map<String, List<String>> m = new HashMap<String, List<String>>();

      假设HashMap提供了如下的静态工厂:

      public static <K, V> HashMap<K, V> newInstance(){

        return new HashMap<K, V>();

      }

      Map<String, List<String>> m = HashMap.newInstance();

      5.静态工厂方法的主要缺点在于,类如果不含公有的或者受保护的构造器,就不能被子类化

      6.静态工厂方法的第二个缺点在于,它们与其他的静态方法实际上没有任何区别。

      valueOf、of、getInstance、newInstance、getType、newType

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

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

      面对必须的参数和可选的参数的构造器:

      1.习惯采用重叠构造器

      写多个构造器,第一个是必须参数的构造器,第二个是必须参数加上一个可选参数组成的构造器,第三个是必须参数加上两个个可选参数组成的构造器....

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

      2.采用javaBeans模式

      创建一个无参的构造器,然后利用setter方法来设置必须的参数以及每个相关的可选参数。  

      javaBeans模式自身的缺点:

        1.构造过程被分到几个调用中,在构造过程中JavaBean可能处于不一致的状态。类无法仅仅通过检验构造器参数的有效性来保证一致性。

        2.JavaBeans模式阻止了类做成不可变的可能。这可能需要程序员付出额外的努力来确保它的线程安全。

      3.采用Builder模式

      既能保证像重叠构造器模式那样的安全性,也能保证像JavaBeans模式那么好的可读性。 不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器(或静态工厂),得到一个builder对象。然后客户端在builser对象上调用类似于setter的方法,来设置每个相关的可选参数。最后,客户端调用午餐的builder方法来生成不可变的对象。

    示例:

    package unit.test.no2;
    
    public class NutritionFacts {
        private final int servingSize;
        private final int servings;
        private final int calories;
        private final int fat;
        private final int sodium;
        private final int carbohydrate;
        
        public static class Builder{
            //Required parameters
            private final int servingSize;
            private final int servings;
            
            //Optional parameters - initialized to default values
            private int calories     = 0;
            private int fat          = 0;
            private int sodium       = 0;
            private int carbohydrate = 0;
            
            public Builder(int servingSize, int servings){
                this.servingSize = servingSize;
                this.servings = servings;
            }
            
            public Builder calories(int val) {
                calories =val;
                return this;
            }
            public Builder fat(int val) {
                fat =val;
                return this;
            }
            public Builder sodium(int val) {
                sodium =val;
                return this;
            }
            public Builder carbohydrate(int val) {
                carbohydrate =val;
                return this;
            }
            
            public NutritionFacts build() {
                return new NutritionFacts(this);
            }
            
        }
        
        
        public NutritionFacts(Builder builder) {
            servingSize = builder.servingSize;
            servings = builder.servings;
            calories = builder.calories;
            fat = builder.fat;
            sodium = builder.sodium;
            carbohydrate = builder.carbohydrate;
        }
        
    }
    View Code

    客户端代码:

      NutritionFactscocaCola = new NutritionFacts.Builder(240,8).calories(100).sodium(35).build();

      builder像个构造器一样,可以对其参数强加约束条件。builder方法可以检验这些约束条件。将参数从builder拷贝到对象之后,并在对象域而不是builder域中对他们进行检验,这一点很重要,如果违反任何约束条件,build方法就应该抛出IllegalStateException。

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

      Singleton指仅仅被实例化一次的类。

      1.公有静态成员是个final域

      public class Elvis{

        public static final Elvis  INSTANCE = new Elvis();

        private Elvis(){...}

        public void leaveTheBuilding(){...}

      }  .

      私有构造器仅被调用一次,用来实例化公有的静态final域Elvis.INSTANCE.

      提醒:享有特权的客户端可借助AccessibleObject.setAccesssible方法,通过反射机制调用私有的构造器。如果想抵御这种攻击,可以修改构造器,让它在被要求创建第二个示例的时候抛出异常。

      2.公有成员是个静态工厂方法

      public class Elvis{

        private static final Elvis  INSTANCE = new Elvis();

        public Elvis(){...}

        public static Elvis getInstance(){ return INSTANCE;}

        public void leaveTheBuilding(){...}

      }

      唯一的优势是提供了灵活性:在不改变API的前提下,我们可以改变该类是否应该为Singleton的想法。  也要考虑第一种的被攻击的情况,抛除其他不相干的优势,第一种public域的方法比较简单。

      当Singleton类变成可序列化的(Serializable)时候?

      直接implements Serializable时,反序列化时都会创建一个新的实例,与Singleton的单例想法相违背。为了维护并保证Singleton,可以参考以下方法:

      1.implements Serializable,并且声明所有的实例域都是瞬时transient的,并提供一个readResolve方法。

      private Object readResolve(){

        return INSTANCE;

      }

      a. transient:仅存在调用者的内存中,而不会写到磁盘里持久化。 (常用在不想序列化的敏感字段(密码,账号等))

      b. readRosolve()是序列化操作提供的一个钩子(hook)---类中具有一个私有的被实例化的方法readResolve()。这个方法确保类开发人员在反序列化会返回怎样的object上具有发言权,虽不是静态的,但反序列化创建实例时会被调用。

      2.从java1.5发行版起,实现Singleton还有第三种方法,只需要编写一个包含单个元素的枚举类型。

      public enum Elvis{

        INSTANCE;

        public void leaveTheBuilding(){...}

      }

      这种方法在功能上与公有域方法相近,但是更加简洁,而且无偿提供了序列化机制,绝对防止多次实例化。可以不在考虑面对复杂的序列化或者反射攻击。 单元素的枚举类型已经成为实现Singleton的最佳方法。

    参考博客:

      Java transient关键字使用小记  http://www.cnblogs.com/lanxuezaipiao/p/3369962.html

      序列化-理解readResolve()       https://blog.csdn.net/fg2006/article/details/6409423

      单例模式的八种写法比较     https://www.cnblogs.com/zhaoyan001/p/6365064.html

  • 相关阅读:
    与IBM的Lin Sun关于Istio 1.0和微服务的问答
    与IBM的Lin Sun关于Istio 1.0和微服务的问答
    与IBM的Lin Sun关于Istio 1.0和微服务的问答
    各种排序算法汇总
    更改一个链接的文本、URL 以及 target
    使用javascript中读取Xml文件做成的一个二级联动菜单
    HTML DOM 实例
    HTML DOM
    js中邦定事件与解绑支持匿名函数
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/muxi0407/p/9030460.html
Copyright © 2020-2023  润新知