使用静态工厂方法替代构造器

优势

  • 该静态工厂方式只是一个返回类实例的静态方法,不同于设计模式中的工厂方法
  • 静态工厂方法有名称,见名知意,如果一个类需要多个构造函数,采用静态工厂方法,可以根据不同的函数名得以理解和区分
  • 不必在每次调用静态工厂方法的时候都创建一个新对象,这种方法类似享元(Flyweight)模式以及单例(Singleton)模式,这些类都能成为实例受控的类,这些类的可以使用 == 代替 equals ,因为 == 对比的是对象的内存地址,equals 是对比对象每个字段的内容,所以 == 效率要高于 equals
  • 静态工厂方法可以返回原对象类型的任意子类对象,可以根据参数的不同返回不同子类对象,同时也可以随着版本的迭代返回不同的子类对象。提高的程序的扩展性和可维护性。
  • 创建泛型实例时,可以使代码变得更简单

    1
    2
    3
    4
    5
    6
    7
    Map<String, List<String>> map = new HashMap<String, List<String>>();
    // 使用静态工厂方法
    public static <K, V> HashMap<K, V> newInstance() {
    return new HashMap<K, v>();
    }
    // 改造后使用方法
    Map<String, List<String>> map = HashMap.newInstance();

缺点

  • 类不含有公有或者受保护的构造器,就不能被子类化
  • 在文档上面并不能和其他静态方法有任何区别

惯用名称

  • valueOf:类型转换,返回实例和参数具有相同的值
  • of:valueOf 更为简洁的写法
  • getInstance:返回的实例通过方法参数来描述,在 Singleton 中该函数没有参数,并返回全局唯一的实例
  • newInstance:每次返回一个新的实例
  • getType:同 getInstance ,Tpye 表示返回对象的类型
  • newType:同 newInstance

构造函数多个参数时使用构造器

建造者(Builder) 模式

用私用构造器或者枚举类型创建 Singleton

单例(Singleton) 模式

  • 序列化问题

通过私有构造函数强化不可实例化能力

有时候需要只包含了静态方法和静态变量这样的工具类,实例化这样的类没有任何意义。不能通过把这样的类设置成抽象类来解决该问题,因为这样该类就可以子类化,误导调用者。此时可以通过把构造函数设置成私有的来解决该问题,不过这样做会有副作用,因为子类访问不到父类的构造函数,所以这样的类不能被子类化

避免创建不必要的对象

  • 如果有类初始化时就确定不变的内容,可以在静态代码块中对这些内容进行初始化
  • 没能重用对象影响程序的风格和性能,但是没能创建重复对象或者保护性拷贝所带来的影响是安全漏洞和错误,当重用对象的代价大于创建重复对象时,应该重新创建对象或者保护性拷贝

消除过期的对象引用

  • 过期引用:永远不会解除的引用
  • 手动清空对象引用应该是一种例外,而不是一种规范行为。消除过期引用的最好方式是让包含改引用的变量结束生命周期
  • 只要类自己管理内存,就应该警惕内存泄漏问题,一点实例被释放掉,该实例中包含的引用对象都应该被消除
  • 借助 Heap 剖析工具发现内存泄漏问题

  • [ ] 内存泄漏

避免使用终结方法

finalize() 会导致行为不稳定、降低性能、以及可移植性问题

  • 不能保证及时执行,JVM 的不同导致 finalize() 执行效果的不同
  • 不能保证可以执行,当对象变成不可达时,对象的 finalize() 没有执行
  • System.gc()、System.finalization() 只能增加 finalize() 被执行的几率
  • 在 finalize() 中,抛出异常时会导致 finalize() 过程结束,使对象处于被破坏状态
  • 添加了 finalize() 后的对象的创建和销毁执行过程比没有添加的用时更长
  • 需要提供显式的终止对象的方式,比如 FileInputStream、FileOutputStream、Timer、Connection