Effective Java
文章平均质量分 94
贺兰猪
这个作者很懒,什么都没留下…
展开
-
【笔记4】通过私有构造器强化不可实例化的能力
【背景】有时候,可能需要编写只包含静态方法和静态域的类。如以java.lang.Math,java.util.Arrays的方式,把基本类型的值或者数组类型上的相关方法组织起来。或者通过java.util.Collections的方式,把实现特定接口的对象上的静态方法组织起来。最后,还可以利用这种类把final类上的方法组织起来,以取代扩展该类的做法。这样的工具类不希望被实例化,实例对它没...原创 2019-06-04 19:28:56 · 185 阅读 · 0 评论 -
【笔记1】考虑用静态工厂方法替代构造器
构造方法创建对象:public Boolean(String s) { this(toBoolean(s)); }//调用Boolean bTrue = new Boolean("true");静态工厂方法创建对象:public static Boolean valueOf(String s) { return toBoolean(s) ? TRUE : ...原创 2019-06-04 15:16:43 · 113 阅读 · 0 评论 -
【笔记2】当构造方法参数过多时使用 builder 模式
构建器使用背景:【参数限制】静态工厂方法与构造器都有一个共同的局限性,就是它们不能很好的扩展到大量的可选参数。1)重叠构造器【使用】第一个构造器是实例化对象必须的参数,第二个会多一个参数,就这样叠加,最后是一个有所有参数的构造器【缺陷】重叠构造器可行,但当有很多的参数的时候,客户端的代码就会很难编写并且不容易阅读2)JavaBeans模式【使用】使用无参的构造方法创建对象,...原创 2019-06-04 16:01:06 · 384 阅读 · 0 评论 -
【笔记3】用私有构造器或者枚举类型强化Singleton属性
Singleton指仅仅被实例化一次的类。Singleton通常被用来代表那些本质上唯一的系统组件,如窗口管理器或者文件系统。在Java1.5发行版本之前,实现Singleton有两种方法。这两种方法都要把构造器保持为私有,并导出公有的静态成员。方法一:公有静态成员是个final域。// Singleton with public final fieldpublic class E...原创 2019-06-04 16:20:32 · 168 阅读 · 0 评论 -
【笔记12】始终要覆盖toString
1、为什么要覆盖toString?java.lang.Object的toString方法的实现:public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode());}这通常不是用户期望看到的,它返回的是类名称+“@”符号+无符号十六进制的散列码。...原创 2019-06-13 19:24:03 · 209 阅读 · 0 评论 -
【笔记8】避免使用 Finalizer 和 Cleaner 机制
【终结方法基本描述】 Finalizer 机制是不可预知的,往往是危险的,而且通常是不必要的。它们的使用会导致不稳定的行为,糟糕的性能和移植性问题。从 Java 9 开始,Finalizer 机制已被弃用,但仍被 Java 类库所使用。 Java 9 中 Cleaner 机制代替了 Finalizer 机制。 Cleaner 机制不如 Finalizer 机制那样危险,但仍然是...原创 2019-06-05 16:37:32 · 394 阅读 · 0 评论 -
【笔记15】使类和成员的可访问性最小化
1. 为什么要使类和成员的可访问性最小化?a.可访问性越低,一个类对外暴露的信息就越少,信息隐藏程度越高,与其它类的耦合程度就更低。b.可访问性越低,也就是封装程度高,具备的意义,跟封装的带来的意义相同。封装的作用a.解除组成系统的各个模块之间的耦合关系,每个模块只需要关注其他模块对外提供的API,各个模块是面向API编程。各个模块可以独立地开发,测试,优化,使用,理解和修改。它...原创 2019-06-17 23:37:05 · 182 阅读 · 0 评论 -
【笔记27】消除非受检警告
非受检警告是什么?非受检警告就是代码上黄色的感叹号 。使用泛型进行编程时,编译器会发出许多警告,如:非受检强制装换警告、非受检方法调用警告、非受检普通数组创建警告以及非受检普通转换警告。为什么要消费非受检警告?1、如果,消除了所有的警告,就可以确定代码是类型安全的,就意味着不会再出现ClassCastException异常,你会更加自信自己的程序可以实现预期的效果。2、如果无法消...原创 2019-07-04 14:55:04 · 204 阅读 · 0 评论 -
【笔记7】消除过期的对象引用
【背景】java虽然有自己的垃圾回收机制,但是并没有那么的智能,对于被引用的对象,就算我们已经不在使用它了,但是java的回收机制是不会回收他们的,人们称之为“内存泄漏”。【内存泄露场景】1.只要类自己管理内存,就该警惕内存泄露问题。如Stack类自己管理内存,在元素出栈,忘记设置为Null时,容易引起内存泄露。import java.util.Arrays;import ja...原创 2019-06-05 14:23:59 · 273 阅读 · 0 评论 -
【笔记18】组合优于继承
继承(inheritance)是实现代码重用的有力手段,但并非总是最好的选择。【本节“继承”指一个类扩展另一个类时的实现继承】与方法调用不同的是,继承打破了封装性。换句话说,子类依赖于超类中特定功能的实现细节。超类的实现有可能随着发行版本的不同而有所变化,一旦发生变化可能导致子类遭到破坏。反例【子类遭到破坏】有一个程序使用HashSet,为了查看它自创建以来曾经添加过多少个元素。我们可...原创 2019-06-19 17:31:20 · 384 阅读 · 0 评论 -
【笔记13】谨慎地覆盖clone
clone方法简介Object 中 clone 方法的定义是:protected native Object clone() throws CloneNotSupportedException;调用clone()方法需要对象实现Cloneable接口,其最主要的缺陷在于,Cloneable接口中不包含任何方法,而Object中的clone方法是protect的,也就是说如果一个类只是...原创 2019-06-15 19:25:57 · 123 阅读 · 0 评论 -
【笔记17】最小化可变性
不可变类只是其实例不能被修改的类。每个实例中包含的所有信息都必须在创建该实例的时候就提供,并在对象的整个生命周期(lifetime)内固定不变。Java平台类库中包含许多不可变的类,其中有String、基本类型的包装类、BigInteger和BigDecimal。存在不可变的类有许多理由:不可变的类比可变的泪更加易于设计、实现和使用。他们不容易出错,且更加安全。为了使类成为不可变,要遵循下面五...原创 2019-06-18 19:33:43 · 261 阅读 · 0 评论 -
【笔记16】在公有类中使用访问方法而不是公共属性
有时候、可能会编写一些退化类(degenerate classes),没有什么作用,只是用来集中实例域:class Point { public double ; public double y; }由于这种类的数据是可以直接被访问的,这些类没有提供封装(encapsulation)的功能。如果不改变API,就无法改变它的数据表示法,也无法强加任何约束条件,当域被访...原创 2019-06-18 18:05:52 · 215 阅读 · 0 评论 -
【笔记10】重写equals时请遵守通用约定
【不覆盖equals的情形】不覆盖equals的情况下,类的每个实例都与它自身相等,如果满足以下任何一个条件,就是所期望的结果:类的每个实例本质上都是唯一的 不关心类是否提供了"逻辑相等"的测试功能 超类已经覆盖了equals,从超类继承过来的行为对于子类也是合适的(要小心)类是私有的或是包级私有的,可以确定它的equals方法永远不会被调用。在这种情况下,无疑是应该覆盖equals...原创 2019-06-06 11:24:14 · 108 阅读 · 0 评论 -
【笔记26】不要使用原始类型
泛型(generic type):声明中具有一个或者多个类型参数的类或者接口的统称。原始类型(raw type):没有任何类型参数的泛型类型的名称。如List<E>对应的原生态类型是List。它们的存在主要是为了与没有泛型之前的代码相兼容。出现泛型前:// Now a raw collection type - don't do this!//这个集合里面应该放sta...原创 2019-07-04 13:56:45 · 4566 阅读 · 0 评论 -
【笔记23】类层次结构优于标签类
标签类:有时候,可能会遇到带有两种甚至更多钟风格的类的实例的类,并包含表示实例风格的(tag)域。例如下面这个类,它能够表示圆形或者矩形://Tagged class - vastly inferior to a class hierarchyclass Figure{ enum Shape{RECTANGLE, CIRCLE}; //Tag field - the shap...原创 2019-06-23 12:47:13 · 126 阅读 · 0 评论 -
【笔记6】避免创建不必要的对象
【situation 1】一般来说,最好能重用对象而不是每次需要的时候就创建一个功能相同的新对象。反例:String s = new String("No way"); //Don't do this!该语句每次被执行都会创建一个新的String实例。传递给String构造器的参数("No way")本身就是一个String实例,功能方面等同于构造器创建的所有对象。如果被频繁调用,会...原创 2019-06-05 12:35:44 · 130 阅读 · 0 评论 -
【笔记20】接口优于抽象类
接口和抽象用来定义允许多个实现的类型。两种机制之间最明显的区别在:① 抽象类允许包含某个方法的实现,而接口则不允许。②为了实现由抽象类定义的类型,类必须成为抽象类的一个子类。Java只允许单继承,所以,抽象类作为类型定义受到了极大限制。接口的优点:现在的类可以很容易的被更新,以实现新的接口。如果这些方法尚不存在,你需要做的就只是增加必要的方法,然后在类的声明中增加一个implemen...原创 2019-06-19 23:50:48 · 318 阅读 · 0 评论 -
【笔记14】考虑实现Comparable接口
1、Comparable接口简介compareTo方法并没有在Object中声明。相反,它是Comparable接口中唯一的一个方法。compareTo方法不但允许进行简单的同等性比较,而且允许执行顺序比较,除此之外,它与Object的equals方法具有相似的特性,还是个涉及到泛型的方法。类实现了Comparable接口,就表明它的实例具有内在的排序关系(natural orderi...原创 2019-06-17 22:07:54 · 240 阅读 · 0 评论 -
【笔记28】列表优先于数组
一、数组与列表容器的比较1、协变与否数组:是协变类型的。协变的意思就是,如果Sub为Super的子类型,那么数组类型Sub[]就是Super[]的子类型。比如说:如果Number是Integer的父类,那么Number[] data = new Integer[]; 是成立的。列表:是不可变类型。就是说List<Number> list = new List<Integ...原创 2019-07-08 19:20:15 · 159 阅读 · 0 评论 -
【笔记11】重写equals时也要重写hashCode
hashcode方法返回对象的哈希码值。hashcode的存在主要用于查找的快捷性,如Hashtable,HashMap等,hashcode是用来在散列存储结构中确定对象的存储地址的。【Object.hashcode通用约定】在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有改变,那么对于这同一个对象调用多次,hashcode方法都必须始终如一地返回同一个整数。...原创 2019-06-06 18:01:12 · 214 阅读 · 0 评论 -
【笔记22】接口仅用来定义类型
当类实现接口时,接口就充当可以引用这个类的实例的类型。因此,类实现了接口,就表明可以对这个类的实例实施某些动作。那么,不是为了这个目的而定义接口就是不恰当的。常量接口有一种接口被称为常量接口,它不满足上述条件,这种接口没有包含任何方法,它只包含静态的final域,每个域都导出一个常量。如下:public interface PhysicalConstants { static...原创 2019-06-22 22:10:11 · 148 阅读 · 0 评论 -
【笔记24】支持使用静态成员类而不涉及非静态类
嵌套类种类嵌套类是指被定义在另一个类的内部的类。嵌套类有四种:静态成员类,非静态成员类,匿名类,局部类。除了第一种,其他三种称为内部类。静态成员类与非静态成员--区别①、持有外部类的引用非静态成员类隐含持有外部类的引用,通过XXClass.this来获取外部类的引用。也就是说能够获取外部类的所用成员变量与成员方法。public class MyType { priva...原创 2019-06-28 20:53:34 · 180 阅读 · 0 评论 -
【笔记19】要么为继承而设计,并提供文档说明,要么就禁止继承
对于专门为了继承而设计并且具有良好文档说明的类而言,该类的文档必须精确地描述覆盖每个方法所带来的影响。该类必须有文档说明它可覆盖的方法的自用性。对于每个公有的或受保护的方法或者构造器,它的文档必须指明该方法或者构造器调用了哪些可覆盖的方法,是以什么顺序调用的,每个调用的结果又是如何影响后续的处理过程的。更一般的,类必须在文档中说明,在哪些情况下它会调用可覆盖的方法。好的API文档应该描述一个给...原创 2019-06-19 22:26:32 · 275 阅读 · 0 评论 -
【笔记38】使用接口模拟可扩展的枚举
枚举类型是不可扩展的,但是接口类型是可扩展的。使用接口,可以模拟可伸缩的枚举。以下是笔记30中Operation类型的扩展版本://只有一个apply方法的接口Operation。public interface Operation { double apply(double x, double y);}//实现接口的计算器public enum BasicOpera...原创 2019-07-21 12:56:08 · 232 阅读 · 0 评论 -
【笔记39】注解优先于命名模式
Java1.5发行版本之前,一般使用命名模式(naming pattern)表明有些程序元素需要通过某种工具或者框架进行特殊处理。例如,JUnit测试框架原本要求他的用户一定要用test作为测试方法名称的开头【Beck04】。这种方法可行,但是有几个很严重的缺点。文字拼写错误导致失败,测试方法没有执行,也没有报错 (JUNIT测试框架测试的方法要用test开头) 无法确保它们只用于相应的程序...原创 2019-07-21 22:18:33 · 110 阅读 · 0 评论 -
【笔记31】利用有限制通配符来提升API的灵活性
如第28条所述,参数化类型是 不可变的(invariant)。对两个不同类型T1和T2而言,List<T1>与List<T2>没有父子类型关系。1、Extends有时候,需要的灵活性要比不可变类型所能提供的更多。考虑第26条中的堆栈下面就是他的公共API:public class Stack<E> { public Stack(); ...原创 2019-07-16 18:08:45 · 163 阅读 · 0 评论 -
【笔记54】返回空的数组或者集合,不要返回null
private final List<Cheese> cheesesInStock = ...;public Cheese[] getCheeses(){ if (cheesesInStock.size == 0) return null;}把没有奶酪可买的情况当做一种特例,这是不合常理的。这样做会要求客户端必须有额外的代买来处理null的返回值。例如...原创 2019-08-08 14:59:34 · 3284 阅读 · 0 评论 -
【笔记36】使用EnumSet代替位属性
如果一个枚举类型的元素主要用在集合中,一般就使用int枚举模式,将2的不同倍数赋予每个常量:// Bit field enumeration constants - OBSOLETE!public class Test { public static final int STYLE_BOLD = 1 << 0; // 1 public static final in...原创 2019-07-20 12:59:33 · 195 阅读 · 0 评论 -
【笔记53】明智审慎地使用可变参数
从Java 1.5开始就增加了可变参数(varargs)方法,又称作variable arity method。可变参数方法接受0个或多个指定类型的参数。它的机制是先创建一个数组,数组的大小为调用位置所传递的参数数量,然后将值传到数组中,最后将数组传递到方法。可变参数的机制原理:1.创建一个array[],它的size就是所传参数的个数;2.将参数放入到array[]中;3.将ar...原创 2019-08-06 19:31:15 · 192 阅读 · 0 评论 -
【笔记29】优先考虑泛型
// Initial attempt to generify Stack = won't compile!public class Stack<E> { private E[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public St...原创 2019-07-09 19:40:53 · 176 阅读 · 0 评论 -
【笔记52】明智审慎地使用重载
public class CollectionClassifier { public static String classify(Set<?> s) { return "Set"; } public static String classify(List<?> l) { return "List"; } ...原创 2019-08-05 20:55:49 · 160 阅读 · 0 评论 -
【笔记35】使用实例属性替代序数
许多枚举天生就与一个单独的int值相关联。所有的枚举都有一个ordinal方法,它返回每个枚举常量在类型中的数字位置。你可以试着从叙述中得到关联的int值:// Abuse of ordinal to derive an associated value -DON'T DO THISpublic enum Ensemble { SOLO, DUET, TRIO, QUIN...原创 2019-07-19 21:16:23 · 154 阅读 · 0 评论 -
【笔记33】优先考虑类型安全的异构容器
泛型最常用于集合,如Set和Map,以及单元素的容器,如ThreadLocal和Atomic Reference。在这些用法中,他都充当被参数化了的容器。这样就限制你每个容器只能有固定数目的类型参数。 但是,有时候你会需要更多的灵活性。例如,数据库行可以有任意多的列,如果能以类型安全的方式访问所有列就好了。幸运的是,有一种方法可以很容易地做到这一点。这种想法就是将键...原创 2019-07-18 23:18:09 · 200 阅读 · 0 评论 -
【笔记30】优先考虑泛型方法
就如类可以从泛型中受益一般,方法也一样。静态工具方法尤其适合于泛型化。Collections中的所有“算法”方法(例如binarySearch和sort)都泛型化了。 编写泛型方法与编写泛型类型相类似。例如下面这个方法,它返回两个集合的联合:public static Set union(Set s1, Set s2) { Set result =...原创 2019-07-13 11:44:21 · 275 阅读 · 0 评论 -
【笔记56】为所有已公开的API元素编写文档注释
为了正确的编写API文档,必须在每个被导出的类、接口、构造器、方法和域声明之前增加一个文档注释。如果类是可序列化的,也应该对他的序列化形式编写文档。为了编写出可维护的代码,还应该为那些没有被导出的类、接口、构造器、方法和域编写文档注释。方法的文档注释应该简洁的描述出他和客户端之间的约定。除了专门为继承而设计的类中的方法之外,这个约定应该说明这个方法做了什么,而不是说明他是如何完成这项工作的。文...原创 2019-08-08 20:02:25 · 211 阅读 · 0 评论 -
【笔记37】使用EnumMap替代序数索引
有时候,会见到利用ordinal方法来索引数组的代码。例如下面这个简化的类,用来表示一种烹饪用的香草:public class Herb { public enum Type { ANNUAL, PERENNIAL, BIENNIAL } private final String name; private final Type type; ...原创 2019-07-20 21:24:27 · 513 阅读 · 0 评论 -
【笔记49】检查参数的有效性
绝大多数方法和构造器对于传递给他们的参数值都会有某些限制。例如索引值必须是非负数,对象引用不能为null,等等。应该在文档中清楚地指明所有这些限制,并且在方法体的开头出检查参数,以强制施加这些限制。这是“应该在发生错误之后尽快检测出错误”这一普遍原则的一个具体情形。抛出异常如果传递无效的参数值给方法,这个方法在执行之前先对参数进行了检查,那么它很快就会失败,并且清楚的抛出适当的异常。如果没...原创 2019-07-23 20:29:37 · 291 阅读 · 0 评论 -
【笔记41】使用标记接口定义类型
标记接口和标记注解定义:标记接口(marker interface):没有包含方法声明的接口,而只是指明一个类实现了具有某种属性的接口。例如,Serializable接口。 标记注解(marker annotation):特殊类型的注解,其中不包含成员。标记注解的唯一目的就是标记声明。例如,@Override。标记接口和标记注解优缺点比较:标记接口有两点胜过标记注解:首先,也是最重...原创 2019-07-22 21:13:51 · 167 阅读 · 0 评论 -
【笔记50】必要时进行保护性拷贝
JAVA是一门安全的语言。这就意味着,它对缓冲区溢出、数组越界、非法指针以及其它的内存破坏错误都自动免疫,而这些错误却困扰着诸如C和C++这样的不安全的语言。在一门安全的语言中,可以确切的知道,无论系统的其他部分发生什么事,这些类的约束都可以保持为真。对于那些“把内存当做一个巨大数组看待”的语言来说,这是不可能的。假设类的客户端会尽其所能来破坏这个类的约束条件,因此你必须保护性的设计程序。考虑...原创 2019-07-24 23:43:30 · 157 阅读 · 0 评论