《Effective Java》知识点(3)--类和接口

15. 使类和成员的可访问性最小化

信息隐藏或封装是软件设计的基本原则之一,因为它可以有效地解除组成系统的各组件之间的耦合关系,即解耦。 应尽可能地使每个类或者成员不被外界访问。

15.1 对于顶层的类和接口,两种访问级别:包级私有的和公有的

15.2 对于成员有四种访问级别:私有的,包级私有的,受保护的,公有的

15.3 公有类的实例域决不能是公有的。包含公有域的类通常不是线程安全的。

15.4 让类具有公有的静态final数组域,或者返回这种域的访问方法,这是错误的。应该私有,用公有方法返回数组的一个拷贝,或者返回一个不可变列表。

16. 要在公有类而非公有域中使用访问方法

如果类可以在它所在的包之外进行访问,就提供访问方法。

如果类是包级私有的,或者是私有的嵌套类,直接暴露它的数据域并没有本质的错误。

公有类永远都不应该暴露可变的数据域。

17. 使可变性最小化

除非有很好的理由要让类称为可变的类,否则它应该是不可变的。如果类不能做成不可变的,仍然应该尽可能地限制它的可变性,尽可能使每个域都是private final的。不要在构造器或者静态工厂之外提供公有的初始化方法。

17.1 为了使类称为不可变,要遵循5条规则:

a. 不要提供任何会修改对象状态的方法(设值方法)

b. 保证类不会被扩展(声明类为final)

c. 声明所有的域都是final的

d. 声明所有的域都是私有的

e. 确保对于任何可变组件的互斥访问

17.2 不可变的优点

a. 不可变对象本质上是线程安全的,它们不要求同步

b. 不仅可以共享不可变对象,甚至可以共享它们的内部信息

c. 不可变对象为其它对象提供了大量的构件

d. 不可变对象无偿地提供了失败的原子性

17.3 不可变的缺点

对于每个不同的值都需要一个单独的对象。创建这些对象的代价可能很高,可能引起性能问题。如果确有性能问题时,才考虑为不可变类提供公有的可变配套类。

18. 复合优先于继承

这里说的继承指的是实现继承,而非接口继承。 继承违背了封装原则,会不必要地暴露实现细节。 只有当子类真正是超类的子类型时,才适合用继承,即"is-a"关系时。

不扩展现有的类,而是在新的类里增加一个私有域,它引用现有类的一个实例,这种设计称为"复合"(composition)。复合不会破坏封装,并且可以隐藏原有类里API的缺陷。应该优先考虑用复合和转发机制来代替继承。

19. 要么设计继承并提供文档说明,要么禁止继承

对于那些并非为了安全地进行子类化而设计和编写文档的类,要禁止子类化(将类声明为final或将所有构造器都变为私有的)。

设计可继承的类,必须

a. 该类必须有文档说明它可覆盖(override)的方法的自用性。即详细说明哪些情况下它会调用可覆盖的方法,调用顺序等等。

b. 类必须以精心挑选的受保护的方法的形式,提供适当的钩子(hook),以便进入其内部工作中。

c. 必须在发布之前编写子类对可继承类进行测试。

d. 为了容许继承,类还必须遵守一些约束。如构造器(还有clone和readObject方法)决不能调用可被覆盖的方法。

20. 接口优于抽象类

接口的优点:

a. 接口可以多继承,可以很容易实现新接口,而抽象类只能单继承。

b. 接口是定义mixin(混合类型)的理想选择,mixin是指提供某些可供选择的行为。

c. 接口允许构造非层次结构的类型框架。

d. 接口使得安全地增强类的功能称为可能。

通过对接口提供一个抽象的骨架实现类,可以把接口和抽象类的优点结合起来。如果你导出了一个重要的接口,就应该考虑提供骨架实现类,且应该尽可能地通过缺省方法在接口中提供骨架实现,以便接口的所有实现类都能使用。另外好的文档绝对是必要的。

21. 为后代设计接口

并非每一个可能实现的所有变体,始终都可以编写出一个缺省方法。

测试每一个新的接口尤其重要,应起码三种实现来测试接口。

22. 接口只用于定义类型

接口应该只被用来定义类型,不应该被用来导出常量。常量应该用不可实例化的工具类或枚举类型来导出。

23. 类层次优于标签类

标签类指含有表明对象类型的变量的类,即用一个类来表示多种对象类型。标签类过于冗长,容易出错,并且效率低下。 应该把标签类转变成类层次,即子类型化。定义公有抽象类,然后根据不同对象类型来定义子类,并且拆分数据域到每个子类。

24. 静态成员类优于非静态成员类

四种嵌套类

24.1 静态成员类

一般作为辅助类。不要求访问外围实例的成员类,都应该是静态的。

24.2 非静态成员类

包含外面类的一个实例引用,这种关联关系消耗空间和时间,可能造成内存泄漏

24.3 匿名类

在使用时同时被声明和实例化。匿名类是使用有很多限制,一般用于创建小型函数对象和过程对象(现在优先选择lambda),或者用在静态工厂方法的内部。

24.4 局部类

在"可以声明局部变量"的地方使用,必须非常简短,不影响可读性。

25. 限制源文件为单个顶级类

一个顶级类一个源文件,永远不要把多个顶级类或者接口放在一个源文件中。这样可以确保编译时一个类不会有多个定义,也能确保编译产生的类文件以及程序结果的行为,都不会受到源文件被传给编译器的顺序的影响。

相关推荐
昙鱼2 分钟前
springboot创建web项目
java·前端·spring boot·后端·spring·maven
eternal__day2 分钟前
数据结构(哈希表(中)纯概念版)
java·数据结构·算法·哈希算法·推荐算法
天之涯上上6 分钟前
JAVA开发 在 Spring Boot 中集成 Swagger
java·开发语言·spring boot
2402_857583498 分钟前
“协同过滤技术实战”:网上书城系统的设计与实现
java·开发语言·vue.js·科技·mfc
白宇横流学长8 分钟前
基于SpringBoot的停车场管理系统设计与实现【源码+文档+部署讲解】
java·spring boot·后端
APP 肖提莫12 分钟前
MyBatis-Plus分页拦截器,源码的重构(重构total总数的计算逻辑)
java·前端·算法
kirito学长-Java13 分钟前
springboot/ssm太原学院商铺管理系统Java代码编写web在线购物商城
java·spring boot·后端
爱学习的白杨树14 分钟前
MyBatis的一级、二级缓存
java·开发语言·spring
Code成立25 分钟前
《Java核心技术I》Swing的网格包布局
java·开发语言·swing
中草药z30 分钟前
【Spring】深入解析 Spring 原理:Bean 的多方面剖析(源码阅读)
java·数据库·spring boot·spring·bean·源码阅读