梦里风林
  • Introduction
  • Android
    • activity
      • Activity四种启动模式
      • Intent Flag
      • 多task的应用
      • Task和回退栈
    • sqlite
      • 【源码】CursorWindow读DB
      • Sqlite在Android上的一个Bug
    • Chromium
    • ListView读取DB数据最佳实践
    • Android Project结构
    • 一个由Proguard与FastJson引起的血案
    • 琐碎的一些tips
  • Computer Vision
    • 特征提取
    • 三维视觉
    • 计算机视觉常用工具
    • 浅谈深度学习数据集设计
    • 随笔
  • Machine Learning
    • 技巧
      • FaceBook: 1 hour training ImageNet
      • L2 Norm与L2 normalize
    • 实践
      • Pytorch实验代码的亿些小细节
    • 工具
      • Tensorflow学习笔记
      • MXNet踩坑手记
      • PyTorch踩坑手记
      • PyTorch模型剪枝
      • Keras踩坑手记
      • mscnn
      • Matlab
        • Matlab Remote IPC自动化数据处理
    • Papers
      • Classification
      • Re-identification
        • CVPR2018:TFusion完全解读
        • ECCV2018:TAUDL
        • CVPR2018:Graph+reid
        • Person Re-identification
        • CVPR2016 Re-id
        • Camera topology and Person Re-id
        • Deep transfer learning Person Re-id
        • Evaluate
      • Object Detection
        • 读论文系列·干货满满的RCNN
        • 读论文系列·SPP-net
        • 读论文系列·Fast RCNN
        • 读论文系列·Faster RCNN
        • 读论文系列·YOLO
        • 读论文系列·SSD
        • 读论文系列·YOLOv2 & YOLOv3
        • 读论文系列·detection其他文章推荐
      • Depth
      • 3D vision
        • 数据集相关
        • 光流相关
      • Hashing
        • CVPR2018: SSAH
      • 大杂烩
        • CNCC2017 琐记
        • ECCV 2016 Hydra CCNN
        • CNCC2017深度学习与跨媒体智能
        • MLA2016笔记
    • 《机器学习》(周志华)读书笔记
      • 西瓜书概念整理
        • 绪论
        • 模型评估与选择
        • 线性模型
        • 决策树
        • 神经网络
        • 支持向量机
        • 贝叶斯分类器
        • 集成学习
        • 聚类
        • 降维与度量学习
        • 特征选择与稀疏学习
        • 计算学习理论
        • 半监督学习
        • 概率图模型
        • 规则学习
        • 强化学习
        • 附录
  • Java
    • java web
      • Servlet部署
      • 琐碎的tips
    • JNI
    • Note
    • Effective Java笔记
  • 后端开发
    • 架构设计
    • 数据库
    • java web
      • Servlet部署
      • 琐碎的tips
    • Spring boot
    • django
    • 分布式
  • Linux && Hardware
    • Ubuntu安装与初始配置
    • 树莓派相关
      • 树莓派3B+无线网卡监听模式
      • TP-LINK TL-WR703N v1.7 openwrt flashing
  • Python
    • django
    • 原生模块
    • 设计模式
    • 可视化
    • 常用库踩坑指南
  • web前端
    • header div固定,content div填充父容器
    • json接口资源
  • UI
  • kit
    • vim
    • git/github
      • 刷爆github小绿点
    • Markdown/gitbook
      • 琐碎知识点
      • gitbook添加disqus作为评论
      • 导出chrome书签为Markdown
      • Markdown here && 微信公众号
    • LaTex
      • LaTex琐记
    • 科学上网
    • 虚拟机
  • thinking-in-program
    • 怎样打日志
  • 我的收藏
  • 琐记
    • 论文心得
    • 深圳买房攻略
  • 赞赏支持
由 GitBook 提供支持
在本页
  • 静态工厂方法代替构造器
  • 构造参数多的时候,使用Builder
  • 私有构造器或枚举类型实现单例
  • 私有构造器强化不可实例化
  • 避免创建不必要的对象
  • 引用泄露
  • Avoid finalize

这有帮助吗?

  1. Java

Effective Java笔记

静态工厂方法代替构造器

  • 有名称,接口比构造器更易懂

BigInteger.probablePrime

  • 可以实现单例、对象池、内存重用

单例模式

  • 可以返回return类型的子类,面向接口编程

    • 可以让返回的类非public

    • 可以通过不同的工厂方法返回不同子类

    Java Collections Framework

  • 利用类型推导,简化模板参数

    Map<String, List<String>> m = HashMap.newInstance();
  • 由于返回的子类型是private,就无法直接实例化这些子类型

  • 静态工厂方法在Javadoc中没有辨识度

  • 常用名称:

    valueOf, of, getInstance, newInstance, getType, newType

构造参数多的时候,使用Builder

  • M1: 多参数重载构造函数

    代码可读性差

  • M2:Java Bean(setter,getter)

    • 简单

    • set过程中对象属性不完整

    • 不能单例化

  • M3:Builder

    public class Line {
      private final int length;
      private final int id;
      public static class Builder {
          private final int id;
          private final int length = 0;
          public Builder(int id) {
              this.id = id;
          }
    
          public Builder length(int len) {
              length = len;
              return this;
          }
          public Line build() {
              return new Line(this);
          }
      }
      private Line(Builder builder) {
          id = builder.id;
          length = builder.length;
      }
      public static void main(String[]args) {
          Line line = new Line.Builder(0).length(1).build();
      }
    }
    • 传递构造参数时像setter一样明确

    • build()调用构造器时,可以执行参数检查进行约束,在build之后才使用返回类,就能保证属性的完整性。

    • 可以向Builder传递模板参数,让它的build()方法返回任意类型

    • Class.newInstance调用无参构造函数,但无参构造函数不存在时,编译不会报错,而Builder的检查则弥补了这一点。

私有构造器或枚举类型实现单例

  • M1:

    public class Elvis {
      public static final Elvis INSTANCE = new Elvis();
      private Elvis() {}
      public void leaveTheBuilding(){}
    }

反射可以调用到私有的构造器

  • M2:

    public class Elvis {
      private static final Elvis INSTANCE = new Elvis();
      private Elvis() {}
      public static Elvis getInstance() {return INSTANCE;}
      public void leaveTheBuilding() {}
    }

灵活,可以通过修改getInstance()方法,决定是否返回单例对象

  • 防止反序列化出错

    private Object readResolve() {
      return INSTANCE;
    }
  • 枚举单例(Java 1.5)

    public enum Elvis {
      INSTANCE;
      public void leaveTheBuilding() {}
    }

简洁,序列化,防止多实例化,最佳方法

私有构造器强化不可实例化

只包含static method和static field的对象不希望被实例化,但实际上它有默认的无参构造器,我们仍然可能实例化它。

因此通过将构造器变为私有防止实例化。

public class UtilityClass {
    private UtilityClass() {
        throw new AssertionError();
    }
}

这种方法的一个缺点是,这种工具类无法被子类化。

避免创建不必要的对象

  • String

    String s = new String("test");

    上面这种写法每次都会重新创建两个String对象

    String s = "test";

    JTS 3.10.5保证了相同内容的字符串重用同一个对象,而且只创建一次。

  • 延迟初始化

  • 单例

  • 对象池

  • 多态层连接单例层,不需要为每个多态层创建多个单例层

  • static执行开销大的代码块,存储执行结果重用

  • 对于一个类中,创建开销大,创建后不修改,但会多次读取的对象,适合

  • 但如果static创建的对象很少使用,可以考虑延迟初始化,但延迟初始化实现复杂,也会影响性能

  • 有些对象初始化后可能改变,但改变后其功能是不变的,应当保持它为一个确定的引用,然后改变引用所指对象的内容,如Map中的keySet

  • 优先使用基本类型(int)而非装箱基本类型(Integer),性能优化

  • 重对象才有必要尽可能避免创建,小对象可以由JVM很容易地构造和销毁,比自己维护对象池要好得多

引用泄露

java中没有内存泄露,只有引用泄露。比如一个Stack的实现:

public class Stack {
    private Object[] elements;
    private int size = 0;
    // ...
    public Object pop() {
        return elements[--size];
    }

}

这里的pop操作只改变了size,而没有将elements[size-1]的引用移除,Stack对象一直持有element的引用,应该改为:

public Object pop() {
    Object result = elements[--size];
    elemets[size] = null;
    return result;
}

通过置null去掉stack中elements数组对element对象的引用

在这个例子中,由于Stack是自己在管理内存,存储池包含了对象引用单元(即elements数组)

需要警惕引用泄露的情形:

  • 类中有对象引用单元

  • 缓存

  • 监听器与回调:bind而没有unbind,好的做法是只保存回调的弱引用。

Avoid finalize

  • Note

    • finalize不保证执行,尽量不要用

    • System.gc和System.runFinalization只是增加finalize执行的机会

    • finalize有严重的性能损失

    • 通过try - catch - finally来显式释放资源

  • 合理用法

    • 作为显式释放资源的backup,或者check

    • 回收native peer

  • 父类finalize

    • 显式调用super.finalize()

    • 内部类强制子类执行

      ```java

      public class Foo {

      private final Object finalizeGuardian = new Object() {

      @Override protected void finalize() throws Throwable {
          Foo.finalize();
      }

      };

      }

上一页Note下一页后端开发

最后更新于6年前

这有帮助吗?