`
woainichenxueming
  • 浏览: 44795 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Effective java学习笔记

阅读更多

 

1静态工厂方法代替构造函

       如:public static Boolean valueOf(boolean){

       return (b? Boolean.TRUE : Boolean.FALSE);

}

一个类提供静态工厂方法的好处a.容易阅读,返回类型明确

                            b.调用时不一定非得产生一个新的对象

                            c.它可以返回一个原返回类型的子类型的对象,返回对象的类型是灵活性更大

                         缺点a.类如果不含共有的或受保护的构造函数,就不能被子类实例化

                              b.他们与普通静态方法没有什么区别。要想在文档中说明如何实例化一个类,是非常困难的。

例如java.util.Collections

2.使用私有构造函数强化singleton属性

     Public class single{

           Public static final single INSTANCE = new single();

           Private single(){}

}

 

Public class single2{

           private static final single2 INSTANCE = new single2();

           Private single2(){}

           Public static single2 getInstance(){

                   Return INSTANCE;

}

}

Single1的好处:组成类的成员的声明很清楚地表明了这个类是一个singleton:公有的静态域是final的,所以该域将总是包含相同的对象的引用。性能要好些

Single2的好处:灵活,在不改变API的前提下,允许我们改变想法,把类改成singleton或者不是singleton

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

      Java.lang.Math  java.util.Arrays

4.避免重复创建对象

     String str = new String(“aaaa”);//Don’t do this

     String str = “aaa”;

   对于同时提供了静态工厂方法和构造函数的非可变类,优先选择静态工厂方法。避免每次调用都产生新的对象

Public class Person{

    Private final Date birthDate;

    Public Person(Date brthDate){

         this.birthDate = birthDate;

}

Public boolean isBadyBoomer(){

    Calender instance = Clender.getInstance(TimeZone.getTimeZone(“CMT”));

    Instance.set(1946,Calender.JANUARY,1,0,0,0);

   Date booleanStart  = instance.getTime();

   Instance.set(1965,Calender.JANUARY,1,0,0,0);

   Date booleanEnd = instance.getTime();

      Return  birthDate.compareTo(booleanStart)>=0&& birthDate.comareTo(booleanEnd) < 0

}

}

不要这样做,每次调用的时候都会实例化一次Calender

Public class Person{

    Private final Date birthDate;

    Public Person(Date brthDate){

         this.birthDate = birthDate;

}

Private static final Date BOOLEANSTART;

Private static final Date BOOLEANEND;

Static{

    Calender instance = Clender.getInstance(TimeZone.getTimeZone(“CMT”));

    Instance.set(1946,Calender.JANUARY,1,0,0,0);

   BOOLEANSTART  = instance.getTime();

   Instance.set(1965,Calender.JANUARY,1,0,0,0);

   BOOLEANEND = instance.getTime();

                         

}

 

Public boolean isBadyBoomer(){

Return birthDate.compareTo(BOOLEANSTART)>=0&& birthDate.comareTo(BOOLEANEND) < 0

}

}

5.消除过期对象引用

   java.util.Stackpop方法elementData[elementCount] = null;

6.避免使用终结函数

Finalizer

显示终止方法的例子InputStreamOutPutStreamclose方法,java.util.Timercancel方法,显示终止方法通常与try—finally结合使用

7.改写equals的时候请遵守通用的约定

A.一个类的每个实例本质上都是唯一的。

B.不关心一个类是否提供了‘逻辑相等(logical equality)’的测试功能。例如java.util.Randomdequals方法。

C.超类已经改写了equals方法。例如Set继承AbstractSet

,List—AbstactList,Map—AbstactMap

   D.一个私有的,包级私有的类。并且equals永远不会被调用

什么时候改写equals呢?当一个类有自己的‘逻辑相等’概念(不同于对象身份的概念),而且超类也没有改写equals以实现期望的行为

改写equals遵循的原则:

自反性:对于任何非空引用值 xx.equals(x) 都应返回 true

对称性:对于任何非空引用值 x y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true

传递性:对于任何非空引用值 xy z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true

一致性:对于任何非空引用值 x y,多次调用 x.equals(y) 始终返回 true 或始终返回 f alse,前提是对象上 equals 比较中所用的信息没有被修改。

对于任何非空引用值 xx.equals(null) 都应返回 false

高质量equals处方:

1.  使用= =操作符检查‘实参是否为指向对象的一个引用’,如果是的话放回true

2.  使用instanceof操作符检查‘实参是否为正确的类型

3.  把实参转换到正确的类型

4.  对于该类的每一个‘关键(significant)’域,检查实参中的域与当前对象中对应得域值是否匹配

Equals告诫:

1.  改写equals是,总是要改写hashCode

2.  不要让equals过于聪明

3.  不要使equals方法依赖不可靠的资源

4.  不要将equals声明的object对象替换为其他的类型例如:public Boolean equals(MyClasss 0){}这样其实是没有override。因为object.equals的实参是object类型。它是overload

8改写equals是总要改写hashCode方法

    hashCode 的常规协定是:

Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。

如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。

以下情况 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。

实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM编程语言不需要这种实现技巧。)

hashCode处方:

1.

把某个非零常数值,比如说1 7,保存在一个叫r e s u l ti n t类型的变量中。

2. 对于对象中每一个关键域f(指e q u a l s方法中考虑的每一个域),完成以下步骤:

a. 为该域计算i n t类型的散列码c

i. 如果该域是b o o l e a n类型,则计算(f ? 0 : 1)

ii. 如果该域是b y t ec h a rs h o r t或者i n t类型,则计算( i n t ) f

iii. 如果该域是l o n g类型,则计算(int)(f ^ (f >>> 32))

i v. 如果该域是f l o a t类型,则计算F l o a t . f l o a t T o I n t B i t s( f )

v. 如果该域是d o u b l e类型,则计算D o u b l e . d o u b l e T o L o n g Bits( f )得到一个l o n g类型的值,然后按照步骤2 . a . i i i,对该l o n g型值计算 散列值。

vi. 如果该域是一个对象引用,并且该类的e q u a l s方法通过递归调用e q u a l s的方式来比较这个域,则同样对这个域递归调用h a s h C o d e。如果要求一个更为复杂的比较,则为这个域计算一个“规范表示(canonical representation)”

,然后针对这个范式表示调用h a s h C o d e。如果这个域的值为n u l l ,则返回0(或者其他某个常数,但习惯上使用0)。

vii. 如果该域是一个数组,则把每一个元素当做单独的域来处理。也就是说,递归地应用上述规则,对每个重要的元素计算一个散列码,然后根据步骤2 . b中的做法把这些散列值组合起来。

b. 按照下面的公式,把步骤a中计算得到的散列码c组合到r e s u l t中:

   result = 37*result + c;

3.返回result

4.检查‘是否相等的实例具有相等的散列码’

9.总要改写toString方法

10.谨慎的改写clone方法

         如果一个类实现了cloneable,则objectclone方法返回该对象的逐域拷贝,否则。它抛出一个cloneNotSupportedException异常

    clone约定:

    创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。一般来说,对于任何对象 x,如果表达式:

x.clone() != x是正确的,则表达式:

x.clone().getClass() == x.getClass()将为 true,但这些不是绝对条件。一般情况下是:

x.clone().equals(x)将为 true,但这不是绝对条件。

按照惯例,返回的对象应该通过调用 super.clone 获得。如果一个类及其所有的超类(Object 除外)都遵守此约定,则 x.clone().getClass() == x.getClass()

 

按照惯例,此方法返回的对象应该独立于该对象(正被克隆的对象)。要获得此独立性,在 super.clone 返回对象之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被克隆对象的内部“深层结构”的所有可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含基本字段或对不变对象的引用,那么通常不需要修改 super.clone 返回的对象中的字段。

 

Object 类的 clone 方法执行特定的克隆操作。首先,如果此对象的类不能实现接口 Cloneable,则会抛出 CloneNotSupportedException。注意:所有的数组都被视为实现接口 Cloneable。否则,此方法会创建此对象的类的一个新实例,并像通过分配那样,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有被自我克隆。所以,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。

 

Object 类本身不实现接口 Cloneable,所以在类为 Object 的对象上调用 clone 方法将会导致在运行时抛出异常

11.考虑实现comparable接口

     CompareTojava.lang.Comparable接口中的唯一对象

     Comparable的规范

     比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。

在前面的描述中,符号 sgn(expression) 表示数学上的 signum 函数,该函数根据 expression 的值是负数、零还是正数,分别返回 -10 1。 实现类必须确保对于所有的 x y,都存在 sgn(x.compareTo(y)) == -sgn(y.compareTo(x))。(这意味着如果 y.compareTo(x) 抛出一个异常,则 x.compareTo(y) 也要抛出一个异常。)

 

实现类还必须确保关系是可传递的:(x.compareTo(y)>0 && y.compareTo(z)>0) 意味着 x.compareTo(z)>0

 

最后,实现程序必须确保 x.compareTo(y)==0 意味着对于所有的 z,都存在 sgn(x.compareTo(z)) == sgn(y.compareTo(z))

 

强烈推荐 (x.compareTo(y)==0) == (x.equals(y)) 这种做法,但不是 严格要求这样做。一般来说,任何实现 Comparable 接口和违背此条件的类都应该清楚地指出这一事实。推荐如此阐述:“注意:此类具有与 equals 不一致的自然排序。”

12.使类和成员的可访问能力最小化

   公有类不应该包含公有域---例外(final修饰的按照惯例大写,下划线分开)

13.支持非可变性

   一个非可变类是一个简单的类,它的实例不能被修改。每个实例中包含的所有信息都必须在该实例被创建的时候就提供出来,并且在对象的整个生存期(lifetime)内固定不变。例如String,原语类型的包装类,bigIntegerBigDecimal。非可变类更加易于设计,实现,使用,它们不容易出错,更加安全

   约束:

   a.不提供任何修改对象属性的方法(mutator

   b.保证没有可被子类改写的方法

   c.使所有的域都是final

   d.使所有的域都成为私有的(不提倡)

   e.保证对于任何可变组建的互斥访问---如果你的类具有指向可变对象的域,则必须确保该类的客户无法获得指向这些对象的引用。并且,永远不要客户提供的对象引用来初始化这样的域,也不要在任何一个访问方法中返回该对象的引用。在构造函数,访问方法和readObject方法中请使用保护性拷贝技术

 

   非可变类的缺点----对于每一个不同的值都要求一个独立的对象,创建这样的对象代价会很高

14.复合优于继承(inhertance

    继承打破了封装性

15.要么专门为继承而设计,并给出文档说明,要么禁止继承

   构造函数一定不能调用可被改写的方法

16.接口优于继承类

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

接口是定义mixin(混合类型)的理想选择。一个混合类型是这样的:一个类除了实现它的‘基本类型(primary type)’之外,还可以实现这个mixin类型以表明它提供了某些可选择的行为

接口使得我们可以构造出非层次结构的类型框架。什么叫骨架实现类

17.接口只是被用于定义类型

   常量接口模式是对接口的不良使用

//Constant utility class

Public class PhysicalConstants{

    Rivate PhysicalConstants(){}

    Public static final double ELECTRON_MASS = 9.1000;

}

接口只是被用来定义类型的,它们不应该被用来导出常量

18.优先考虑静态成员类

嵌套类(nested class)是指被定义在另一个类的内部的类。嵌套类存在的目的应该只是为他外围类提供服务。如果一个嵌套类将来可能会用于其它的某个环境中,那么它应该是顶层类(top-level class)。嵌套类有四种:静态成员类(static member class),非静态成员类(nonstatic member class),匿名类(anonymous class)和局部类(local class)。出了第一种之外。其它三种都被称为内部类(inner class

静态成员类是一种最简单的嵌套类。最好把它看成一个普通的类,只是碰巧被声明在另一个类的内部而已,它可以访问外围类的所有成员,包括哪些声明为私有的成语。

匿名类常见用法:1.创建一个函数对象—comparator实例

        Arrays.sort(args,new Comarator(){

              Public int comare(Object o1,Object o2){

                  Return ((String)o1).length() - ((String)o2).length();

}

});

2.创建一个过程对象,比如ThreadRunnable或者TimerTask实例

3.在一个静态工厂方法的内部

4.复杂的类型安全枚举类型

19.用类代替结构

20.用类层次来代替联合

21.用类代替enum结构

22.用类和接口来代替函数指针

23.检查参数的可用性

     例如索引必须是非负数,对象引用不能为null

24.需要时使用保护性拷贝

25.谨慎设计方法的原型

   谨慎选择方法的名字

   不要过于追求提供便利的方法

   避免长长的参数列表

   对于参数类型,优先使用接口而不是类

   谨慎使用函数对象

26.谨慎使用重载

27.返回零长度的数组而不是null

28.为所导出的api编写文档注释

29.将局部变量的作用域最小化

    for(int i=0;i< list.size();i++){

   doSomthing....

}

for(int i = 0; n = list.size();i<n;i++){

   doSommething;

}

下面一个效率要高一些

30.了解和使用库

31.如果需要精确的答案,请避免使用floatdouble

32.如果其他类型更合适,则尽量避免使用字符串

   字符串不适合代替其他的值类型

   字符串不适合代替枚举类型----类型安全枚举类型(typesafe enum)和int值比较适合

   字符串不适合代替聚集类型

字符串不适合代替

0
1
分享到:
评论

相关推荐

    effective java 读书笔记

    《Effective Java》是Java开发领域的经典著作,作者Joshua Bloch深入浅出地阐述了编写高效、健壮的Java代码的技巧和最佳实践。以下是对该书部分内容的详细解释: 1. **产生和销毁对象** - Item1:静态工厂方法相比...

    effectiveJava的笔记

    以下是对《Effective Java》笔记中可能涉及的关键知识点的详细解读: 1. **单例模式**:书中强调了如何正确实现单例模式,推荐使用`enum`来创建线程安全且唯一的实例,避免传统双重检查锁定的潜在问题。 2. **构造...

    Effective-Java读书笔记

    《Effective Java》是Java...以上仅是《Effective Java》一书中部分核心知识点的概述,实际的读书笔记中会更详细地解释这些概念,并给出具体的示例代码。通过深入学习和实践,开发者可以极大地提升其Java编程的水平。

    读书笔记:Effective Java中文版学习项目.zip

    读书笔记:Effective Java中文版学习项目

    java入门级学习笔记

    【Java入门级学习笔记】 ...总之,Java学习笔记旨在为初学者提供全面的学习路径,从基础知识到核心概念,再到实际应用,逐步构建扎实的Java编程基础。通过持续学习和实践,你可以逐渐掌握这门强大且多用途的语言。

    Effective Java.zip

    《Effective Java》是一本经典Java编程指南,作者是Joshua Bloch,这本书深入探讨了...以上内容仅是《Effective Java》各章节的部分知识点概述,书中还有更多关于Java编程的最佳实践和深入理解等待读者去发掘和学习。

    java学习书籍

    以下是一些关于Java学习书籍的知识点,这些书籍可以帮助你从入门到精通,全面提升你的Java编程技能。 1. **《Java核心技术卷》**:这套书籍通常分为两卷,卷I主要涵盖基础知识,如语法、数据类型、控制结构、类和...

    5本java学习用书

    让我们逐一探讨这些书籍及其在Java学习中的价值。 1. **《21天学通JAVA》**:这本书通常被推荐为初学者入门的读物,它以简洁易懂的方式介绍了Java的基础知识,包括语法、数据类型、流程控制、面向对象编程概念等。...

    java学习PDF下载地址全 百度云盘下载

    本资源集合提供了一份完整的“Java学习PDF”,旨在帮助学习者系统地理解和掌握Java编程。 这份PDF教程可能涵盖以下关键知识点: 1. **Java简介**:介绍Java的历史、特点、应用领域以及与其它编程语言的对比,使...

    java7hashmap源码-for-java:java学习笔记

    Java学习笔记 Effective Java Topic2:插件销毁对象 2. 多参数情况 使用重叠构造器; 使用Build模式【构建器】: new A.Build().set.set.build(); Build模式也适用于类层次结构 递归类型参数 /* * 递归类型参数: ...

    java8源码-esmusssein777.github.io:我的学习记录

    同时,`effectiveJava学习笔记`可能包含了对《Effective Java》这本书中最佳实践的学习心得,这本书对于提升Java编程技巧非常有帮助。Java 8的实战学习笔记则可能涵盖了将新特性应用到实际项目中的经验分享。通过...

    java-note:Java学习笔记

    Structure /src/main/java ... ├ effective_java Effective Java 中文第二版 ├ jvm 深入理解Java虚拟机:JVM高级特性与最佳实践 ├ lambda JAVA 8实战 ├ netty Netty权威指南 ├ oop ├ recursion

    JAVA学习百度云资料

    2. **2018年黑马程序员最新Java学习笔记**:这份笔记是由专业教师精心整理的,包含济南校区的精华教学内容,不仅覆盖了基础理论,还有实践案例,是学习过程中的重要参考资料。链接:...

    Java开源项目汇总.pdf

    * CS-Notes:Java学习笔记,涵盖了Java的基础知识、数据结构、算法、设计模式等。 * advanced-java:Java高级教程,涵盖了Java的高级知识、Java设计模式、Java框架和工具等。 Java实战 * miaosha:Java电商项目,...

    这些年学习JAVA的资源,包括工具和资源包

    比如Awesome Java集合了各种Java资源,Java-Interview提供了面试准备资料,JDK源码阅读笔记帮助理解Java内部机制,Java设计模式实现则涵盖了各种设计原则,而Java学习笔记提供了从JavaSE到JavaWeb的逐步学习路径。...

    drools学习笔记

    对于学习 drools 的初学者,理解这些基础概念至关重要,它们将帮助你构建复杂的规则系统,实现业务逻辑的自动化和智能化。在实际应用中,根据需求灵活运用这些特性,可以极大地提升软件系统的可维护性和扩展性。

    notes:JavaJava后端工程师的学习笔记https

    loveincode's notes 学习工作中的一些记录,收藏。 操作系统 , 编译原理 , 计算机网络 , 互联网协议... 常用数据结构与算法 Java 实现 数据结构 与 排序算法 ...Effective Java , HTTP权威指南 , Java

    leetcode题库-MyNote:`13的学习笔记

    的学习笔记 学习笔记与练习项目源码整理 The Only Easy Day Was Yesterday 编程语言 C 参考书籍 : 《c primer plus》 6th edition 书内习题答案总结 , 优秀源码赏析 快速平方根算法 kilo (1000行的源文本编辑器) ...

    下面是我对于JAVA学习的一些心得体会

    学习JAVA是一种深度探索的过程,它不仅要求我们掌握基础语法,还需要理解其...学习多元化的编程语言和文化,可以拓宽视野,使你在JAVA学习的道路上更加游刃有余。通过这些方法,相信你可以成为一名出色的JAVA开发者。

    Maven 2 学习笔记.txt

    ### Maven 2 学习笔记 #### 一、Maven 项目的基本结构及创建 Maven使用特定的目录结构来组织项目文件,通过`mvn archetype:create`命令可以快速创建项目模板。例如: ```shell mvn archetype:create -DgroupId=...

Global site tag (gtag.js) - Google Analytics