【序】今天睡懒觉了,差点咕咕咕。(手动换行) 昨天试图分享自己的笔记,结果被吐槽只是抄书。这句话的对做为尝试写总结性质读书笔记的新手(我)的打击性其实是很大的。花了近3小时写的文章(姑且算是),结果被别人看了一眼就说你这就是抄书,没有技术含量,也不算是原创。
-
无能狂怒:这是本人初次尝试通过记录笔记并公开分享,也是尝试对费曼学习法的一次尝试,如果你不喜欢或者觉得没有任何价值。只能抱歉,这确实是我的问题,请自行关闭。这个系列我还是会写,可能后期渐渐改变写作风格。当前的格式很受此书的影响(这本书本来就是总结性质的),只能说前几篇确实是写得太过于仓促有一点依葫芦画瓢的感觉吧。
-
为什么做这个系列:在才开始看
EffectiveJava
的几天,我其实是并没有这个打算的,因为此书本身是总结性质的,但是由于有不少的地方比较难,在网上搜索相关的内容大多都是完整的抄书没有得到实质性的讲解。所以打算自己总结来加深理解。 -
定位:帮助自己学习和理解JAVA,当然希望对别人有用。
16、在公共类中使用访问方法而不是公共属性
关键字:public类
,访问方法
,public属性
在JAVA
里面,对于那些需要对外提供某些属性的类。比较建议的一种写法是对外提供访问方法(getter
和setter
)而不直接将这些属性设置为public
的。曾经有人问过我这个问题,为什么要这么做,我并不知道,只觉得这是封装思想的一种体现。
如下(例子源于书上):
//不建议这样写
class Point {
public double x;
public double y;
}
//建议这样写
class Point {
private double x;
private double y;
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
}
理解:
- 这其实是类和成员可访问性最小化的一个体现。外界通过唯一
public
的API
来获取数据。类本身将其具体的实现隐藏,这样内部的实现无论怎么改只要返回给外界他们期望的值即可。相对的,如果直接将属性提供给外界的话,那么在一个成型的代码系统中,这个属性就几乎没有再修改的余地了。
例外:
- 如果一个类是包级私有的或者是一个私有的内部类,这样写是被允许的。理由很简单,它们对外提供的属性的作用范围太小了,并不会出现上面提到的那种问题。而且这样写的可读性更强,不是吗?(手动斜眼)
17、最小化可变性
关键字:可变性
首先我们给不可变的类一个基本的定义:
- 不提供任何修改对象状态的方法
- 不能被继承
-
所有的属性均为final。(即便这个属性是
private
的,因为你无法保证在编写逻辑的时候不修改某个属性的值,而设置为final
后,当你不经意修改的时候会出现错误提醒你) -
所有的属性应该是private的。(其实设置为
public
并不会出现任何问题,但是这违背了条目16的建议) - 确保对任何可变组件的互斥访问。(这是什么意思呢???)
理解:
-
在创建的一开始它的状态就被确定了,状态在它存在的整个生命周期均不会发生任何改变。
-
线程安全的,不需要线程同步。因为不可变的对象的所有属性都是只读的,它并不会因为多线程的同时访问而出现同步问题。
-
可以自由的分享,也没有必要创建很多个副本或者考虑防御性拷贝。
缺点:
为每一个不同的值都需要创建一个单独的对象,导致性能问题。
总结:
除非有很好的理由能够说明一个类应该是可变的,否则尽量将其设置为不可变的。
18、组合由于继承
关键词:组合
,继承
跨越包级的继承很危险(对类来说)的。
- 破坏了封装的思想:子类有可能会依赖父类的一些实现细节,但是父类改变后,可能会导致子类无法使用。
- 重写父类的方法不一定有效:在出现了上面的问题的时候,一个解决方案就是重写父类的方法,但是如果这个逻辑涉及到一些父类中的私有属性的话,那么将无法实现。(子类并不能访问父类的私有属性)
- 随着父类新版本的发布,父类可能会提供新的方法。但是这可能会对子类进行破坏(如果正好子类拥有一个相同名字参数和返回类型的方法),从而导致编译不通过。
组合:
不继承一个现有的类,而是在新的类里面持有一个私有的现有类的对象。对于现有类的一些实现,新的类实现一个同名方法并在内部调用现有类的方法。
优点:
- 新类并不依赖现有类的实现细节,所以现有类的修改并不会对新类产生影响。
理解:
- 这是一种基于包装类的思想,即设计模式中的装饰者模式。
- 这种设计模式并不等同于委托
注意:
- 包装类中不适合使用回调,因为某一些设置回调的方法对象会将自我的引用返回出来,但是被包装的对象是并不知道它的外界存在一个包装器,所以它仍然会返回一个自身的引用。
总结:
适合使用继承的情况:只有子类真的是父类的子类型的情况下才适合使用继承。即两者中存在"B is A"的关系,才应该让B继承A。
19、要么设计继承并提供文档说明,要么就禁用继承
如题,字面意思。
可继承的类:
-
如果一个类是可以被继承的话,那么我们应该提供详细的文档说明
- 详细描述重写某一个方法会带来的影响。
- 应当说明可重写方法的自用性
- 应当详细的列出任何可能调用可重写方法的情况
-
测试一个为继承而设计的类的唯一方法是编写子类进行测试
-
构造方法里面不能直接或间接地调用可重写的方法
禁用继承:
- 如果无法提供很好的设计或文档,那么就将此类设置为final以禁用继承
总结:
- 设计一个可继承的类需要提供详细的文档,并且需要很大程度上限制这个类的功能。
- 如果不得不继承一个没有提供详细文档的类,最好的方法是不调用任何可重写的方法(消除父类自用可重写方法的可能性)。
20、接口优于抽象类
关键字: 接口
,抽象类
JAVA
对于抽象类只允许单一继承,而对于接口来说可以多实现。
理解:
JAVA对类的继承的结构是垂直的,也就是说一个类继承了它的父类,那么它就一定满足"A is B"的描述,也就是说,它的根源是被确定了的。
但是接口只是一种实现,它对外表述的是"A can be B",这表示A是多变的,它强调了A是具有某一些行为是符合它被作为B的要求,所以它应该是有多种实现的。
- 抽象类过分的强调了层级关系,这对于我们并不能准确定义某一些类的层次。比如说一个程序员也可能是一个作家,但是如果使用抽象类我们就无法给它一个精确的定义。
- 实现了接口的类可以很方便的实现其他接口以更新功能,但是如果是实现了抽象类,那么就会比较麻烦。
- 接口是定义
mixin
(混合类型)的理想选择,它保证了一个类除了提供自身类型以外,还能够提供某些可以选择的行为。
相关链接:
EffectiveJava笔记[一]
EffectiveJava笔记[二]
EffectiveJava笔记[三]
网友评论