学习一门语言
一门新的语言,需要了解
1,这么语言的结构如何;
2,如何命名你想谈论的事物;
3,如何以惯用和高效的方式来表达日常的事物。
语言的核心、词汇表、惯用和高效的表达方式。
个人思考:
1,从多个维度去理解语言。形成、演进、问题的出现和解决、从写到执行的过程。
2,我在学习过程中犯得错误。
3,有哪些改进是我现在可以做的。
第一条:考虑用静态工厂方法代替构造器
静态工厂方法(static factory method):返回类的实例的静态方法。
静态工厂方法与构造器不同的优势
1,它们有名称;
2,不必在每次调用它们的时候都创建一个新对象;
使得不可变类可以使用预先构建好的实例,或者将构建好的实例缓存起来,进行重复利用,从而避免创建不必要的重复对象。
总能严格控制在某些时刻哪些实例应该存在,这种类被称作实例受控的类。可以确保它是一个Singleton或者是不可实例化的。可以确保不会存在两个相当的实例,即当且仅当a==b时才有a.equals(b)为true。
3,可以返回原返回类型的任何子类型的对象;
静态工厂方法返回的对象所属的类,在编写包含该静态工厂方法的类时可以不必存在,这种灵活的静态工厂方法构成了服务提供者框架(Service Providers Framework)的基础:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来。
服务提供者框架有三个重要的组件:服务接口(Service Interface),提供者实现的;提供者注册API(Provicer Registration API),系统用来注册实现,让客户端访问的;服务访问(Service Access API)客户端用来获取服务实例的。第四个组件(可选的):服务提供者接口(Service Provider Interface):负责创建其服务实现的实例。
4,在创建参数化类型实例的时候,使代码变得更加简洁。
缺点
1,类如果不包含共有的或者受保护的构造器,就不能被子类化;
2,它们与其他的静态方法实际上没有任何区别。
第二条:遇到多个构造器参数时,要考虑用构建器
类的构造器或者静态工厂中,具有多个参数时,可选的模式:
1,重叠构造器模式
2,JavaBeans模式
3,Builder模式:不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器,得到一个Builder对象;然后客户端在Builder对象上调用类似于Setter的方法,来设置每个相关的可选参数;最后客户端调用无参的builder方法来生成不可变的对象。
Builder模式模拟了具名的可选参数。
Builder模式的不足:
1,为了创建对象,必须先创建它的构造器。
2,Builder模式比重叠构造器模式更加冗长。
第三条:用私有构造器或者枚举类型强化Singleton属性
Singleton指仅仅被实例化一次的类。
第四条:通过私有构造器强化不可实例化的能力
第五条:避免创建不必要的对象
第六条:消除过期的对象引用
如果一个栈是先增长,然后再收缩,那么,从栈中弹出的对象将不会被当做来及回收,即使使用栈的程序不再引用这些对象,它们也不会被回收。这是因为栈内部维护这对这些对象的过期引用(obsolete reference)。所谓的过期引用,是指永远不会再被解除的引用。
(Stack类自己管理内存)
只要类是自己管理内存,程序员就应该警惕内存泄漏问题。
内存泄漏另一个常见来源是缓存。
内存泄漏第三个常见来源是监听器和其他回调。
第七条:避免使用终结方法
终结方法通常是不可预测的,也是很危险的,一般情况下是不必要的。
终结方法的缺点在于不能保证会被及时的执行。
显示的终止方法通常与try-finally结构结合起来使用,以确保及时终止
第八条:覆盖equals时请遵守通用约定
约定:
1,自反性
2,对称性
3,传递性(无法在扩展可实例化类的同时,既增加新的值组件,又保持equals约定)
4,一致性
高质量equals的方法
1,使用“==”操作符检查“参数是否为这个对象的引用”。如果是,则true。
2,使用instanceOf操作符检查“参数是否是正确的类型”。
3,把参数转换成正确的类型。
4,对于该类中的每个关键域,检查参数的域是否与该对象中对应的域匹配。
5,当编写完equals方法时,问自己三个问题:它是否是对称的、传递的、一致的。
一些告诫
覆盖equals时总要覆盖hashCode方法
不要企图让equals方法过于智能
不要讲equals方法中的Object对象替换为其他的类型
第九条:覆盖equals时总要覆盖hashCode
Object规范之一:
如果两个对象根据equals方法比较是相等的,那么这两个对象的hashCode方法也是相等的。(相等的对象必须有相等的散列码)
一个好的散列函数倾向于“为不相等的对象产生不相等的散列码”,理想情况下,散列函数应该把集合中不相等的实例均匀的分布到所有可能的散列值上。
一个散列函数的简单实现:
1,把某个非零的常数值,比如17,保存到一个名为result的int类型的变量中;
2,对于对象中的每个关键域f(equals方法中涉及的每个域),完成以下步骤:
a,为该域计算int型的散列码c:
a1,如果该域为boolean类型,则计算(f:1,0)
a2,如果该域是byte,char,short,int类型,则计算(int)f
a3,如果该域是long类型,则计算((int)(f(异或符)f>>>32))
a4,如果该域是float类型,则计算Float.floatToIntBits()
a5,如果该域是double类型,则计算Double.doubleToLongBits(),然后按照步骤a3,未得到的long类型计算散列值。
a6,如果该域是一个对象引用,并且该类的equals方法通过递归递归的调用equals方法来比较这个域,则同样为这个域递归的调用hashCode,如果需要更复杂的比较,则为这个域计算一个范式,然后对这个范式调用hashCode。如果这个域为null,则返回0(或者其他某个常数,但通常是0)
a7,如果该域是一个数组,则要把每一个元素当做单独的域来处理,也就是说,递归的应用上述规则,对每个重要的元素计算一个散列码,然后根据b中的算法将这些散列码组合起来。如果数组域中的每个元素都很重要,可以使用Arrays.hashCode方法
b,按照下面的公式,把a中计算得到的散列码合并到result中
result=31*result+c
3,返回result
4,检查“相等的实例是否都具有相等的散列码”。
第10条:始终要覆盖toString方法
类的名称@散列码的无符号十六进制表示法
toString方法应该返回对象中包含的所有值得关注的信息。
理想情况下,字符串应该是自描述的。