Effective Java 笔记
1. 静态工厂
- 静态工厂的第 5 个优点是,在编写包含该方法的类时,返回的对象的类不需要存在。他的意思是面向接口编程??就是说我们只需知道接口,具体实现类是否存在没有关系??
- 只提供静态工厂方法的主要限制是,没有公共或受保护构造方法的类不能被子类化。子类不能够继承父类,想要用父类的方法,只能复合。
public class SubBookOrder {
BookOrder bookOrder = null;
public void SubBookOrderTest() {
bookOrder = BookOrder.getTotalPrice("bookName", 10, 23.50);
bookOrder.getTotalPrice();
}
}
2. builder模式
JavaBean模式缺陷。
不幸的是,JavaBeans 模式本身有严重的缺陷。由于构造方法在多次调用中被分割,所以在构造过程中 JavaBean
可能处于不一致的状态。该类没有通过检查构造参数参数的有效性来执行一致性的选项。在不一致的状态下尝试使用对象可能会导致与包含 bug 的代码大相径庭的错误,因此很难调试。一个相关的缺点是,JavaBeans 模式排除了让类不可变的可能性(条目 17),并且需要在程序员的部分增加工作以确保线程安全。第一点:使用JavaBean将无法区分哪些是必须哪些是可选。
第二点:有setter的话,这样类实例之后就能够修改了,不能保证线程安全。
有效性检查。意思是对参数有效性的检查,比如是否为null,是否符合物理常识(比如物体质量不能为负)。
Pizza.Builder 是一个带有递归类型参数( recursive type parameter)(条目 30)的泛型类型。 这
与抽象的 self 方法一起,允许方法链在子类中正常工作,而不需要强制转换。 Java 缺乏自我类型的这种变通解决
方法被称为模拟自我类型(simulated self-type)的习惯用法。Pizzal类
abstract static class Builder<T extends Builder<T>>
// Subclasses must override this method to return "this"
protected abstract T self();
NyPizza类
public static class Builder extends Pizza.Builder<Builder>
@Override protected Builder self() {return this;}
请注意,每个子类 builder 中的 build 方法被声明为返回正确的子类: NyPizza.Builder 的 build 方法返回 NyPizza ,而 Calzone.Builder 中的 build 方法返回 Calzone 。 这种技术,其一个子类的方法被声明为返回在超类中声明的返回类型的子类型,称为协变返回类型(covariant return typing)。 它允许客户端使用这些builder,而不需要强制转换。
abstract Pizza build(); @Override public NyPizza build() {return new NyPizza(this);} @Override public Calzone build() {return new Calzone(this);}
3. 单例模式
- 通过私有构造方法
- 通过静态工厂
- 通过枚举类
4. 使用私有构造方法执行非实例化
- 比如Math或Arrays等类就不需要实例化,他们都是调用静态方法来完成事情。当然由于构造方法私有,该类的子类就不能访问父类构造方法,也就是说该类不能子类化。
5. 依赖注入优于硬连接资源
通过依赖注入的方式,而不是写死的方式,来引入依赖资源,这样会极大 增强类的灵活性,可重用性和可测试性。
6. 避免创建不必要的对象
String s = new String("bikini"); 不好
String s = "bikini"; 好
有限状态机(Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
还有基本类型和装箱类型,如果使用装箱类型就会创建新对象,所以要我们注意自动装箱,他可能会创建很多不必要的对象。
7. 消除过期的对象引用
当对象在栈中弹出不会被垃圾回收,这是因为栈对这些对象的过期引用。所以需要我们将他们设置成null;
8. 避免使用 Finalizer 和 Cleaner 机制
看不懂,反正不用就对了。。。
9. 使用 try-with-resources 语句替代 try-finally 语句
当必须close的资源时,要使用try-with-resources,这样会更简洁清晰,生成的异常更有用。
10. 重写 equals 方法时遵守通用约定
重写equals方法是有些约定,要满足自反性,一致性,对称性,传递性,非空性,IDE和AutoValue 框架提供了自动生成,这些都遵守以下:
- 使用 == 运算符检查参数是否为该对象的引用。如果是,返回 true。这只是一种性能优化,但是如果这种比较可
能很昂贵的话,那就值得去做。- 使用 instanceof 运算符来检查参数是否具有正确的类型。 如果不是,则返回 false。 通常,正确的类型是
equals 方法所在的那个类。 有时候,改类实现了一些接口。 如果类实现了一个接口,该接口可以改进 equals 约
定以允许实现接口的类进行比较,那么使用接口。 集合接口(如 Set,List,Map 和 Map.Entry)具有此特性。- 参数转换为正确的类型。因为转换操作在 instanceof 中已经处理过,所以它肯定会成功。
- 对于类中的每个“重要”的属性,请检查该参数属性是否与该对象对应的属性相匹配。如果所有这些测试成功,
返回 true,否则返回 false。如果步骤 2 中的类型是一个接口,那么必须通过接口方法访问参数的属性;如果类型
是类,则可以直接访问属性,这取决于属性的访问权限
11. 当覆盖 equals 时,始终覆盖 hashCode
当进行equals比较时,先比较对象的hashCode,然后再去比较对象的每个属性是否相等。如果不重写hashCode,那么即使是相等的对象,最终返回结果也可能是false。
12. toString
toSting当然也可以自动生成。如果对生成的字符串没有格式要求,那么自动生成的是好的。但是如果对于生成的字符串有格式要求,比如phonenumber,这时用自动生成就不太好了。
//这就是有格式要求的toString方法
@Override
public String toString() {
return String.format("%03d-%03d-%04d",areaCode, prefix, lineNum);
}
13. 谨慎地重写 clone 方法
通常,复制功能最好由构造方法或工厂提供。 这个规则的一个明显的例外是数组,它最好用 clone 方法复制。
// Copy constructor
public Yum(Yum yum) { ... };
// Copy factory
public static Yum newInstance(Yum yum) { ... };
14. 考虑实现 Comparable 接口
//使用静态 compare 方法:
// Comparator based on static compare method
static Comparator<Object> hashCodeOrder = new Comparator<>() {
public int compare(Object o1, Object o2) {
return Integer.compare(o1.hashCode(), o2.hashCode());
}
};
//或者使用 Comparator 的构建方法:
// Comparator based on Comparator construction method
static Comparator<Object> hashCodeOrder =
Comparator.comparingInt(o -> o.hashCode());
15. 使类和成员的可访问性最小化
显而易见这是为了封装解耦,JDK使用了模块级别,但是普通程序员还是不要使用模块来控制访问。在公共类中的公共静态final除了作为常量以外,不应该有公共属性。确保 public static final 属性引用的对象是不可变的(如果是可变的,那么客户端就能对其访问并修改,造成安全漏洞)。
如果你想用这个数组:
public static final Thing[] VALUES = { ... };
但是又害怕客户端对其进行修改,可以进行如下操作:
你可以使公共数组私有并添加一个公共的不可变列表:
private static final Thing[] PRIVATE_VALUES = { ... };
public static final List<Thing> VALUES =
Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
或者,可以将数组设置为 private,并添加一个返回私有数组拷贝的公共方法:
private static final Thing[] PRIVATE_VALUES = { ... };
public static final Thing[] values() {
return PRIVATE_VALUES.clone();
}
16. 在公共类中使用访问方法而不是公共属性
当然,对于公共类来说,坚持面向对象是正确的:由于这些类的数据属性可以直接被访问,因此这些类不提供封装的好处(条目 15)。 如果不更改 API,则无法更改其表示形式,无法强制执行不变量,并且在访问属性时无法执行辅助操作。
如果直接访问共有属性而不是方法,到时候我们想更改一些业务逻辑就没法了。
17. 最小化可变性
如果你创建一个类,最好是不可变类,除非你有性能上的要求,需要有可变伙伴类。比如String和StringBuilder。类中属性最好是final,但有时为了性能在一个不可变类中也可能有公共可变属性。
18. 组合优于继承
看不懂。
50. 必要时进行防御性拷贝
即使编写的代码是没有set方法的,但是由于所依赖的类是可变的,而导致所编写的类也是可变的。比如Date是一个可变类。
public final class Period {
private final Date start;
private final Date end;
/**
* @param start the beginning of the period
* @param end the end of the period; must not precede start
* @throws IllegalArgumentException if start is after end
* @throws NullPointerException if start or end is null
*/
public Period(Date start, Date end) {
if (start.compareTo(end) > 0)
throw new IllegalArgumentException(
start + " after " + end);
this.start = start;
this.end = end;
}
public Date start() {
return start;
}
public Date end() {
return end;
}
... // Remainder omitted
}
虽然此类没有set,但是由于Date类可变(Date类有set方法),导致该类也是可变的。
Effective Java 笔记的更多相关文章
- Effective Java笔记一 创建和销毁对象
Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...
- Effective java笔记(二),所有对象的通用方法
Object类的所有非final方法(equals.hashCode.toString.clone.finalize)都要遵守通用约定(general contract),否则其它依赖于这些约定的类( ...
- effective java笔记之单例模式与序列化
单例模式:"一个类有且仅有一个实例,并且自行实例化向整个系统提供." 单例模式实现方式有多种,例如懒汉模式(等用到时候再实例化),饿汉模式(类加载时就实例化)等,这里用饿汉模式方法 ...
- effective java笔记之java服务提供者框架
博主是一名苦逼的大四实习生,现在java从业人员越来越多,面对的竞争越来越大,还没走出校园,就TM可能面临失业,而且对那些增删改查的业务毫无兴趣,于是决定提升自己,在实习期间的时间还是很充裕的,期间自 ...
- Effective java笔记(一),创建与销毁对象
1.考虑用静态工厂方法代替构造器 类的一个实例,通常使用类的公有的构造方法获取.也可以为类提供一个公有的静态工厂方法(不是设计模式中的工厂模式)来返回类的一个实例.例如: //将boolean类型转换 ...
- Effective java笔记(四),泛型
泛型为集合提供了编译时类型检查. 23.不要在代码中使用原生态类型 声明中具有一个或多个类型参数的类或接口统称为泛型.List<E>是一个参数化类,表示元素类型为E的列表.为了提供兼容性, ...
- Effective java笔记(九),并发
66.同步访问共享的可变数据 JVM对不大于32位的基本类型的操作都是原子操作,所以读取一个非long或double类型的变量,可以保证返回的值是某个线程保存在该变量中的,但它并不能保证一个线程写入的 ...
- Effective java笔记(八),异常
57.只针对异常的情况才使用异常 try { int i = 0; while(true) range[i++].climb(); }catch(ArrayIndexOutOfBoundsExcept ...
- Effective java笔记(七),通用程序设计
45.将局部变量的作用域最小化 将局部变量的作用域最小化,可以增强代码的可读性和可维护性,并降低出错的可能性. Java允许在任何可以出现语句的地方声明变量(C语言中局部变量要在代码块开头声明),要使 ...
- Effective java笔记(六),方法
38.检查参数的有效性 绝大多数方法和构造器对于传递给它们的参数值都会有限制.如,对象引用不能为null,数组索引有范围限制等.应该在文档中指明所有这些限制,并在方法的开头处检查参数,以强制施加这些限 ...
随机推荐
- jenkins+docker+nginx+tomcat实现vue项目部署
一.项目准备 1.新建一个vue的项目,确保能在浏览器正常访问.然后在项目的根目录下新建一个Dockerfile的文件,内容如下 FROM nginx COPY dist /usr/share/ngi ...
- 看完我的笔记不懂也会懂----git
Git学习笔记 - 什么是Git - 首次使用Git - DOS常用命令 - Git常用命令 - 关于HEAD - 版本回退 - 工作区.暂存区与版本库 - git追踪的是修改而非文件本身 - 撤销修 ...
- deepin-terminal改造之路
目录 1. 背景介绍 2. 下载源码 3. 依赖检查及安装 4. 改造之路 4.1 终端透明度快捷键 4.1.1 设置面板增加选项内容 4.1.2 添加配置解析内容 4.1.3 功能实现 4.1.4 ...
- Java-Socket通信 知识点记录
目录 一.Socket基本案例 二.消息通信 2.1 双向通信 2.2 告知发送结束 2.2.1 通过Socket关闭 2.2.2 通过Socket关闭输出流的方式 2.2.3 通过约定符号 2.2. ...
- Python3+pygame实现的90坦克大战 代码完整 有演示效果
我是一个典型的80后,年轻时玩过了特别多的游戏,所以这几天用Python3+pygame实现了一个另外小游戏"坦克大战"(其他的游戏,请翻阅我的博客) 本实例代码量有些多,完整的版 ...
- C++图论算法——图的储存方式
使用二维数组邻接矩阵储存图 无向图: 图G 定义图G[101][101],G[i][j]的值表示从结点vi到vj是否有边或弧,若有,取值为1或权值,若无,则取值为0或∞.以下是图G用邻接矩阵表示的列表 ...
- 史上超强拷贝仓——GitHub 热点速览 v.21.11
作者:HelloGitHub-小鱼干 Clone-Wars 是真的强,能细数 70+ 知名应用网站的源码,即便你不看代码,也可以了解下各大网站的所用技术栈.同样很强的是用 OpenCV 实现的图片转 ...
- C#上机实验(三)
源码如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespac ...
- 【JVM进阶之路】一:Java虚拟机概览
1.Java简史 Java语言是一门通用的.面向对象的.支持并发的程序语言.全球从事Java相关开发的人员已经数以百万计. 从1995年"Java"正式出现以来,Java已经经历了 ...
- 实验四 Python综合实践
课程:<Python程序设计> 班级:1843 姓名:章森洋 学号:20184307 实验教师:王志强 实验日期:2020年5月16日 必修/选修: 公选课 1.实验内容 此处填写实验的具 ...