第二章

作者: gcno93 | 来源:发表于2021-12-29 00:31 被阅读0次

    如何创建一个对象,什么时候创建
    如何避免创建对象
    如何适时的销毁对象
    如何管理销毁对象的时候,必须进行的各种清理动作

    第一条 用静态工厂方法替代构造器
    如何创建一个对象
    1.提供一个公有的构造器
    2.提供一个公有的静态工厂方法
    1.静态工厂方法比构造器方法的优势
    1.静态工厂方法,它有名字,而构造器只能通过不同的参数列表来区分
    2.静态工厂方法,不必在每次调用他们的时候都创建一个新的对象,
    单例,不可实例化的类,不可变的类,缓存对象,实例受控的类,类似于享元模式
    3.静态工厂方法,他们可以返回原返回类型的任何子类型的对象,在java8中,支持接口创建静态方法,
    可以把这个静态方法放到接口中
    4.静态工厂方法,所返回的对象的类可以随着每次调用而发生改变,这取决于静态工厂的参数值,
    随着版本不同可以返回不同的对象,只要是返回对象的子类即可,
    EnumSet根据枚举类型的大小来创建不一样的对象实例
    5.静态工厂方法,方法返回的对象所属的类,在编写包含该静态工厂方法的时候可以不存在,
    服务提供者框架(jdbc)使用class.forName()加载具体的drive
    java自带的ServiceLoader类 /META-INF/service/接口的全限定名,内容是具体的接口实现类
    2.静态工厂方法比构造器方法的缺点
    1.类如果不包含公有的或者受保护的构造器,就不能被子类化,所以鼓励使用复合,而不是继承
    2.程序员很难发现他们,在api文档中没有像构造函数那样明确的标识出来
    3.静态工厂方法命名
    1.from 类型转换 Date.from(instan)
    2.of 聚合方法 EnumSet.of(JACK,QUEEN,KING)
    3.valueOf BigInteger.valueOf(544546)
    4.instance,getInstance(),返回的实例是通过方法的参数来描述的,但不能说与参数具有同样的值,
    StackWalker luke = StackWalker.getInstance(options)
    5.create,newInstance(),跟instance,getInstance()一样,但是确保每次调用都返回一个新的实例,
    Object newArray = Arrays.newInstance(classObject,arrayLen)
    6.getType,像getInstance(),但是在工厂方法处于不同的类中的时候使用 FileStore fs = Files.getFileStore(path)
    7.newType,像newInstance(), 但是在工厂方法处于不同的类中的时候使用
    8.type,getType和newType的简化版 List<Complaint> litany = Collections.list(legacyLitany)

    第二条 遇到多个构造器参数时要考虑使用构建器
    1.存在大量可选参数时,如何编写对象
    1.重叠构造器,客户端代码会很难编写,并难以阅读
    2.javabean模式,也就是说先使用无参构造器创建对象,然后使用setter方法设置必要的参数,
    在构造的过程中javaBean可能处在不一致的状态,如果一个类不是不可变的类,那么可能存在线程问题
    3.建造者模式的一种形式
    1.模拟了具名的可选参数
    2.也适用于类层次结构
    3.如果类的构造器或者静态工厂中具有多个参数,设计这种类时,builder模式是一个不错的选择

    第三条,利用私有构造器或者枚举类型强化singleton属性
    1.构造器私有,导出公有的静态成员,防止反射调用私有构造函数,可以在构造函数中判断,存在就抛出异常
    2.构造器私有,公有成员是静态工厂方法,防止序列化,需要添加public Object readResolve()
    3.枚举类型,单例的最佳实践

    第四条,利用构造函数强化不可实例化的能力
    1.让类包含一个私有的构造器,它就不能被实例化,比如,Arrays,Collections,Math类

    第五条,优先考虑依赖注入来引用资源
    1.静态工具类和单例类不适合于需要底层资源的类
    2.当创建一个新的资源时,就将该资源传到构造函数中,这是依赖注入的一种形式
    3.也可以使用资源工厂来创建资源,supplier(供应商,最符合资源工厂),然后把工厂传进构造器

    第六条,避免创建不必要的对象
    当对象的创建比较昂贵的时候,重用对象可以提高程序的行能,但是不要盲目的重用对象,
    维护轻量级对象的对象池并不是一个好的做法,它必定会把代码弄得很乱,增加内存,损害性能
    1.字符串 new String("sds")是错误的,s = "sds"才是对的
    2.string.matches("")会创建一个pattern实例,这个是成本很高的,应该复用pattern实例
    3.map的keySet 返回的是同一个Set对象
    4.自动拆装箱,优先使用基本数据类型而不是装箱基本数据类型,要当心自动的装箱

    第七条,消除过期的对象引用
    1.数组元素的删除,删除数组元素不是长度减1,还需要array[size] = null 清理过期的数组元素对象
    2.只要自己管理内存,程序员就要警惕内存泄漏的问题
    3.清空对象引用应该是一种例外,而不是一种规范行为
    4.内存泄漏的另一个来源是缓存,使用WeakHashMap,只有当所要的缓存项的生命周期是由键的外部引用,
    而不是值决定时,WeakHashMap才有用处;定时清除过期的对象;添加的时候顺便清理过期对象
    5.内存泄漏的第三个来源是监听器和其他回调,把回调保存成WeakHashMap的键,也就是弱引用

    第八条,避免使用终结方法和清除方法
    1.终结方法(finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的
    2.清除方法(cleaner)没有终结方法那么危险,但是仍然是不可预测,运行缓慢,一般情况下也是不必要的
    3.终结方法和清除方法不能保证会被及时的执行,注重时间的任务不应该由终结方法或者清除方法来完成
    4.终结方法和清除方法,在不同的jvm中运行的表现可能截然不同
    5.终结方法和清除方法不保证及时,还不保证会被执行,永远不应该依赖终结方法或者清除方法来更新
    重要的持久状态,比如,释放共享资源上的锁,可能导致锁无法被释放
    6.使用终结方法和清除方法有一个严重的性能损失
    7.终结方法有一个严重的安全问题,从构造器抛出异常,应该足以防止对象继续存在;有了终结方法
    的存在,这一点就做不到了,为了防止非final类受到终结方法的攻击,要编写一个空的final的finalize方法
    8.终结方法和清除方法的好处,当资源的所有者忘记调用它的close方法,终结方法和清除方法可以充当安
    全网,索然不能保证及时运行,但是客户端无法正常操作的情况下,吃一点释放资源总比不释放的好;
    第二个合理的用途,对象的本地对等体有关,本地对等体是一个本地对象(不是java对象),普通对象
    通过本地方法委托给一个本地对象,当普通java对象被回收时,本地对等体不会被回收,这时终结方法
    和清除方法正是执行这项任务最合适的工具

    第九条 try-with-resources 优先与try-finally
    1.try会抛异常,finally也会抛异常,而却finally的异常可能会覆盖try的异常
    2.实现autoCloseable接口
    3.保留第一个异常,禁止后一个异常,禁止的异常也不是被抛弃,还是会打印在堆栈轨迹中,
    并注明他们是被禁止的异常,通过编程调用getSuppressed方法还可以方法到它,Throwable.getSuppressed()

    1. try-with-resources 可以使用catch

    相关文章

      网友评论

          本文标题:第二章

          本文链接:https://www.haomeiwen.com/subject/bqamqrtx.html