CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛

《EffectiveJava》读书笔记-永久免费的源码丞旭猿

来自:CSDN(作者:iCoding91)

原文链接:

https://blog.csdn.net/caoxiaohong1005/article/details/79521960

1.静态工厂方法

  • 相对公有构造器的优势

    • 有名字。

      静态工厂方法可以根据功能定义名字,但构造器名字都是类名。

    • 不必每次调用时都创建对象。

      如果经常请求创建相同的对象,并且创建对象的代价很高,则这项技术可以极大的提高性能。

    • 可以返回原返回类型的任何子类型。

      这样在选择返回类时,更加灵活。

    • 在创建参数化实例的时候,它们使得代码更加简洁。

  • 缺点

    • 类如果不含有公有的或者受保护的构造器,就不能被子类化。

      因为在创建子类对象时,需要调用到父类的公有无参数构造器方法。

    • 它们与其他的静态方法实际上没有任何区别。

      因为在API文档中未被明确标记,因此对于提供了静态工厂方而不是构造器的类来说,要想查明如何实例化一个类,这是非常困难的。

  • 总结

    静态工厂方法和公有构造器各有用途,但是应该首选考虑用静态工厂方法替代构造器。

2.Singleton实现机制

  • 三种方式:

    • 功能上和公有域近似。

    • 优势:

    • 代码简洁

    • 无偿提供序列化机制

    • 防止多次序列化

    • 构造器方法设置为private,导出一个final的public静态成员。

    • 构造器方法设置为private,利用公有静态工厂方法导出final的private静态成员。

    • 包含单个元素的枚举类型

  • 总结:

    • 单元素的枚举类型是实现Singleton的最佳方式,是jdk1.5开始有的。

    • 前两种方式核心思想:

      构造器设置为private+导出公有静态成员

3.内存泄漏的3个来源

  • 类自己管理内存

    • 解决办法:

      一旦元素被释放,就应该将该元素中包涵的任何对象引用清空。

    • 例子:

      Stack类,存放元素的数组为elementData。

      在pop操作后,就应该执行

      elementData[elementCount] = null;

      从而使得GC可以对它里面保存引用的对象进行清理(elementData中保存的是对象引用,而不是对象本身)

  • 缓存

    • 缓存应定时清掉无效的项。

      这项清理工作可以由一个后台线程来完成

    • 在给缓存添加条目时顺便进行清理

    • 解决办法

  • 监听器和其他回调

    • 解决办法:

      回调立即被当作垃圾回收的最佳方式是:

      只保存它们的弱引用。

      弱引用:被弱引用关联的对象只能生存到下一次垃圾回收之前

4. equals()方法分析

  • 覆盖equals时的通用规定

    • 自反性:

      对象必须等于自身

    • 对称性:

      任何两个对象对于它们是否相等的问题都必须保持一致。

    • 传递性:

      a和b相等,b和c相等,则a和c相等。

    • 一致性:

      如果两个对象相等,则它们始终保持相等,除非它们中有一个被修改了。

    • 非空性:

      所有的对象都必须*不等于*null

      常见错误用法:

      许多类的equals方法第一句都是:

      if(o==null) return false;但这样写是冗余的。

      因为equals方法在把参数转为适当类型前,必须调用instanceOf操作符,检查其参数是否为正确的类型。

      null在进行instanceOf检查类型时,如果传入参数为null,则直接返回false。

  • 高质量equals()书写原则:

    • 使用==操作符检查参数是否为这个对象的引用。

      如果是,则返回true。

      这是一种性能优化,如果比较操作可能很昂贵,则值得这么做。

    • 使用instanceOf操作符检查参数是否为正确的类型。

    • 把参数转换成正确的类型。

    • 对该类中每个关键域,检查参数中的域是否与该对象中对应的域匹配。

      查看jdk源码可以发现,基本都是这样写的,格式完全一致

  • 常用用法说明:

    • 非float、double的基本类型,直接用==进行比较即可。

    • 对象引用域,则递归调用equals方法。

    • 对于float域,则用Float.cmopare()方法。

    • 对于double域,则用Double.compare()方法。

  • 覆写equals时,必须覆盖hashCode()方法

    • 这一点很重要,因为任何两个equal的对象,在调用hashCode()方法时,必须返回同一个整数。

5.接口vs抽象类

  • 最大区别

    为实现抽象类定义的类型,类必须为抽象类的子类。

  • 接口的优势

    • 现有的类可以很容易被更新,以实现新的接口

      对于一个新的接口,如果一个类想实现它,则只要在类的声明中添加一个implement子句,同时override接口中的方法即可。

    • 接口时定义mixin(混合类型)的理想选择

      mixing类型是指:

      类除了实现它的基本类型以外,还可以实现这个mixin类型,以表明它提供了某些可供选择的行为。

      比如JKD中的Clone接口、Comparable接口。

      一个类如果实现了Comparable接口,则表明这个类的实例可以和其它的可相互比较的对象进行排序。

    • 接口允许构造非层次结构的类型框架

6.列表vs数组

  • 不同点

    • 数组是协变的,泛型是不可变的。

      协变:如果Sub为Super的子类型,则数组类型Sub[]为Super[]的子类型

      不可变:任意两个不同的类型Type1和Type2,List既不是List的子类型,也不是List的超类型

    • 数组是具体化的。

      数组元素的类型:在程序运行时才检查类型约束

      泛型:在编译时强化类型信息,运行时擦除类型信息

  • 为什么创建泛型数组是非法的?

    因为它不是类型安全的。

    因为数组元素的类型检查发生在运行时,如果定义了一个泛型数组,则其类型不能在编译时进行检查,如果定义出现错误,则会在程序运行时发生ClassCastException异常。

    这就违背了泛型系统提供的保证。

    因为泛型是在编译时进行类型检查,故不会出现运行时的ClassCastException。

7.可变参数

  • 机制

    • 先创建一个数组

    • 然后将参数值传入到数组中

    • 最后将数组传递给方法

  • 性能问题

    可变参数方法的每次调用都会导致进行一次数组分配和初始化。

8.基本类型vs装箱类型

  • 主要区别

    • 基本类型只有值,而装箱类型则具有与它们的值不同的同一性。

      解释:换句话说,两个装箱基本类型可以有相同的功能值,但是有不同的同一性。

    • 基本类型只有功能完备的值,但装箱类型除了有对应的功能值之外,还有一个非功能值null。

    • 基本类型比装箱类型节省空间和时间。

  • 装箱类型的合理用处

    • 作为集合中的元素、键、值

      – 在参数化类型中,必须使用装箱类型

    • 在进行反射方法的调用时,必须使用装箱类型

9.native方法

  • 定义

    是指本地程序设计语言(比如c或者c++)来编写的特殊方法

  • 用途

    • 提供了访问特定于平台的机制的能力

    • 提供了访问遗留代码库的能力

  • 缺点

    • 程序不再能免受内存损坏错误的影响。

      因为本地语言是不安全的

    • 程序不再可自由移植。

      因为本地语言是与平台相关的

    • 程序难调试

    • 进入和退出native方法需要相关开销

    • 需要胶合代码的本地方法编写起来单调乏味,难以阅读

10.序列化

  • 序列化的代价

    • 最大代价是:

      一旦一个类被发布,就大大降低改变这个类的实现的灵活性

      如果一个类实现了Serializable接口,它的字节流编码就变成了它的导出API的一部分。一旦这个类被广泛使用,往往必须永远支持这种序列化形式。

    • 它增加了出现Bug和安全漏洞的可能性。

      因为序列化机制是一种语言之外的对象创建机制,反序列化机制都是一个隐藏的构造器,因为没有显示的构造器,所以很容易忘记确保:反序列化过程必须也要保证由真正的构造器建立起来的约束关系,并且不允许攻击者访问正在构造过程中的对象的内部信息。

    • 随着类发行新的版本,相关的测试负担增加。

    • 当一个可序列化的类被修订时,很重要的一点就是:检查是否可以在新版本中序列化一个实例,然后在旧版本中反序列化,反之亦然。

  • 使用默认序列化的缺点

    • 它使得这个类的导出API永远束缚在该类的呃内部表示法上

    • 消耗过多的空间

    • 消耗过多的时间

      因为序列化逻辑不了解对象图的拓扑关系,所以它必须要经过一个昂贵的图遍历过程。

    • 引起栈溢出

      默认的序列化过程要对对象图执行一次递归遍历,即使对于中等规模的对象图,也可能引起栈溢出。

    推荐阅读:

    喜欢我可以给我设为星标哦

    好文章,我在看

声明:本文部分素材转载自互联网,如有侵权立即删除 。

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
相关推荐
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容