第二章 创建和销毁对象
规则1 考虑以”static factory mehthods”取代构造函数
提供一个公共静态工厂方法返回一个类的实例
优势:
有名字, 不需要每次都建立一个新的实例, 可以复用对象, 还可以返回类型的子类
能够保证是单例类, 能够保证不会有两个相同的实例存在
没有构造函数的类不能被子类化.
不容易和其他静态方法区分开
常见的是valueof和getInstance方法
规则2 用私有构造函数构建单例模式
规则 3 用私有构造函数构造工具类避免被实例化
规则 4 避免创建重复对象
对象如果是不可变的总是可以被复用, String就是不可变对象, 为了避免创造重复对象而使用静态工厂方法, Boolean.valueOf(String)比构造函数Boolean(String)好, 构造函数需要每次都建立新的对象, 而静态工厂方法则不需要.
本规则中的两个例子很好, 但关于适配器中的两个例子没有看.
适配器对象用来提供可选择的接口给返回的对象, 因为适配器没有状态, 所以没有必要建立超过一个实例, 举的keySet的例子, map接口的keySet方法返回Set, 由于Set是个接口, 所以Set虽然只有一个实例, 但可以得到不同的实现.
避免创建重复对象不意味着新建对象很昂贵或是可以避免, 相反, 建立和申明小的对象开销小, 特别是现代的JVM.
另一方面, 维护自己得对象池是个坏主意除非在对象池中的对象实在太耗资源,
规则5 消除过期的对象
如果类管理了自己的内存, 就要注意将过期的对象销毁, 当对象被读出后, 对象的地址仍然被保存在数组中, 这些地址是不会被对象回收器回收的.
为什么垃圾回收器不能回收array管理的内存, 垃圾回收器的原理, 它能回收怎样的资源, 它在什么时候回收资源?
规则 6:避免finalizer
规则 7 //TODO
第三章 所有对象通用的方法
// TODO
第四章 对象和接口
规则 12把类和成员的可访问范围降到最低
应该保证类变量具有尽可能少的可视性, 常量可以申明为公共的, 一个好的模块隐藏了所有的实现细节, 这样可以把模块之间的耦合程度降到最低.
如果一个顶级类或是接口, 能够定义为包私有, 那就定义为包私有.
如果一个包-私有的顶级类或是接口仅仅被一个类使用, 应该考虑使它成为类的私有内部类, 当然这个并没有将顶级类该为包私有来的重要, 因为毕竟它已经是包私有的了, 通常public的类不应该有public的字段, 通常会用一个类来定义所有的常量.
以前从来没有注意过这一点, 从来都是定义类为public, 而不考虑类的使用范围.
没有定义长度的数组总是可变的, 不能定义为public static final array 字段, 客户端能够修改数组的内容,
public static final Type[] Values = {}; //wrong
private static final Type[] PRIVATE_VALUE = {};
public static final List VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUE));
规则 13不可修改的类更受青睐
不可修改类是指其实体不能被修改的类, 包含在类实体内的所有信息都在创建时提供, 并在生存期内固定不变, 不可变类是线程安全的, 不会因为多线程存取而破坏.
不要提供任何可供修改的方法
保证没有任何方法可以被覆写(将类定义为final)
所有类变量都必须是private
确保对任何可变组件的互斥存取
不可变类能够重用已经存在的类的实例, 最简单的方法是提供一个经常使用得公共常量.
不但可以共享不变的对象, 还可以共享他们内部资源.
不变对象为其它对象建立了很好的代码块. 不用担心他们的值在map或set中会变化.
唯一的缺点是要为每一个不同的值建立一个对象.
//TODO
需要进一步理解copy和clone方法
规则14 优先考虑复合, 然后才是继承
规则 15 除非专为继承而设计并提供文件, 否则不要使用继承
规则 16 在接口和抽象类之间优先选择前者
抽象类和和接口最明显的区别是抽象类允许实现一部分方法, 而接口需要实现全部方法.
规则 17 接口只用来定义类型
当一个类继承了一个接口时, 接口作为一个类型能够用来引用类的实例, 继承接口的类用来说明类的实例可以为客户端做什么, 为其他目的定义接口是不合适的.
不应该用接口来定义常量, 实现常量接口会导致实现的细节泄漏给类的API, 如果将来类修改不再需要常量, 仍然要实现接口来保证兼容性, 如果一个非final类继承了常量接口, 所有它的子类都会有接口的这些常量.
如果常量紧密的关联类或是接口, 应该把常量加入类或接口, 如果常量可以作为一个枚举类型的成员,应该在一个类型安全的枚举类型中定义, 其他, 应该定义在一个不变的工具类中定义.
规则 18 在静态和非静态内部类之间选择前者
静态成员类是最简单的嵌套类, 它是最好的嵌套类的选择, (and has access to all of the enclosing class’s members, even those declared private)能够获得所有类变量, 哪怕是私有的类变量, 这句话有问题, 静态成员类只能获得外部类静态的字段, 相反非静态成员类却能获得任何字段, 所以这点不见得是优点它是类的静态成员, 具有和其他静态成员一样的可视性.
静态成员类的一个常见的应用是作为公共的辅助类, 用来连接外部的类
每个非静态成员类的实例都会和父类的实例相关联, 非静态成员类的方法能够调用父类的方法,
Given a reference to an instance of a nonstatic member class, it is possible to obtain a reference to the encloing instance.
在没有父类实例的情况下, 不能够建立非静态成员类的实例.
非静态成员类的一个普通应用是定义适配器.
如果定义一个成员类不需要获得父类的实例, 那么定义成静态成员类. 如果不这样做的话, 每个实例都会有一个父类的引用.
匿名类不像java语言里的任何东西, 它没有名字, 它不是类的成员, 只要表达式合法它能够定义在类的任何地方, 行为是否象静态类或是非静态类取决于它在哪里定义.
由于匿名类没有名字, 所以它仅仅能用在初始化后不需要再在父类引用它的场合, 它仅能实现父类或是接口的方法, 而不能申明任何新的方法, 由于他们发生在表达式中间, 所以不能太长, 太长的话会影响程序的可读性.
一个典型的引用是建立功能对象
Arrays.sort(args, new Comparator(){
Public int compare(Object o1, Object o2){
Return ((String)o1.length()-((String)o2).length();
}
});
另外一个应用是建立处理对象, 象Thread, Runnable, 或是TimerTask的实例, 第三个应用是静态工厂方法, 第四个应用是publi static final 字段的初始化.
如果一个嵌套类能够被方法外读取或是在方法体内太长, 使用成员类, 如果父类实例需要成员类的引用, 使用非静态成员类, 其他情况使用静态成员类,
第五章 C构造器的替代
规则 18 静态成员类超越非静态成员类
一个内嵌类是定义在其他类里面的类, 有四种内嵌类, 非静态成员类, 成员类, 匿名类, 本地类, 只有第一种被称为内部类.
每个非静态成员类和它的母类相关联, 不可能调用母类的方法, 不可能建立一个非成员类而不建立母类.
一个非成员类的普通的用法是定义适配器
规则 21 用类来代替枚举类型
名义上, 这个结构定义了一个枚举类型, 合法值由一组固定常数组成. 实际上, enum结构并不能很好的定义枚举类型. 它只是定义了一系列的整型常量的名字, 并没有对类型安全有很大作用
类型安全的枚举模式
public class Suit{
private final String name;
private Suit(String name) {this.name = name;}
public String toString() {return name;}
public static final Suit CLIBS = new Suit(“cllubs”);
public static final Suit DIAMONDS = new Suit(“diamonds”);
}
第六章 方法
规则 23 检查参数的有效性
每次写一个方法或是构造函数的时候, 应该想想参数有什么限制, 应该将这些限制文档化, 并且要求在方法体开始前做显示的检查.
规则 24 在需要的时候做保护性拷贝
public class Box {
private int length;
public void setLength(int length){
this.length = length;
}
public int getLength(){
return this.length;
}
}
public class TestJava {
private String id;
private int idx;
private Box box;
public void setId(String id){
this.id = id;
}
public String getId(){
return this.id;
}
public void setIdx(int idx){
this.idx = idx;
}
public int getIdx(){
return this.idx;
}
public void setBox(Box box){
this.box = box;
}
public Box getBox(){
return this.box;
}
public static void main(String[] args) {
TestJava tj = new TestJava();
String id = "tony";
int idx = 5;
Box aBox = new Box();
aBox.setLength(7);
tj.setId(id);
tj.setIdx(idx);
tj.setBox(aBox);
System.out.println(tj.getId());
System.out.println(tj.getIdx());
System.out.println(tj.getBox().getLength());
id = "bai";
idx = 6;
aBox.setLength(8);
System.out.println(tj.getId());
System.out.println(tj.getIdx());
System.out.println(tj.getBox().getLength());
}
}
//output:
tony
5
7
tony
5
8
String类和Number类都是immutable的, 所以String和int类的对象会copy出一个不同于原对象的对象, 而原来的对象状态并未被修改, Box不是immutable所以被外部修改了
public void setBox(Box box){
this.box = new Box();
this.box.setLength(box.getLength());
}
public Box getBox(){
Box aBox = new Box();
aBox.setLength(this.box.getLength());
return aBox;
}
修改后的output:
tony
5
7
tony
5
7
在实践中“为类中immutable class类型(如String和数值Number类)的field member写setter/getter时,我们不需要提供defensive copy;在为其它非immutable class类型(如上例中的Box类)的field member写setter/getter时,建议考虑defensive copy,以防止client对你的代码的恶意破坏”。
保护性拷贝应该在参数合法化检查之前.
规则 25 小心的设计方法签名
小心的选择方法名字
The Java Developers Almanac中包含了任何单个方法的签名. 但是没有找到具体的方法
避免太长的方法签名
三个方法名字是最长的方法签名
两种方法改变方法签名, 将一个方法变为多个方法, 建立一个静态帮助类用来放所有的参数, 但是为什么要用静态类呢? 这些帮助类是静态的成员类. //没有看明白
参数尽量使用接口
使用功能对象
需要配合规则18重看
规则 26 明智的使用重载
规则 27 返回0长度的数组, 而不是 njll
第七章 一般性编程
规则 29 将本地变量的范围降到最低
在第一次用的时候申明成员变量.
几乎所有的成员变量都需要一个初始值
如果没有足够的信息初始化一个变量, 应该推迟初始化直到获得信息为止.
For循环允许申明循环变量, 限制他们的作用范围在他们需要的区域, 因此for比while循环更好.
For(Iterator I=c.iterator(); i.hasNext();){
DoSomething(i.next());
}
Iterator I=c.iterator();
While(i.hasNext()){
DoSomething(i.next());
}
…
Iterator i2 = c2.iterator();
While(i.hasNext()){
DoSomethigElse(i2.next()); // BUG
}
第二个循环包括了一个剪切和粘贴错误
for(Iterator I = c.iterator(); I.hasNext();){
doSomething(i.next());
}
…
// 编译错误 I 不能被解释
for(Iterator i2 = c2.iterator(); I.hasNext();){
doSomething(i2.next());
}
第一个for循环的变量I 在第二个循环中不能编译通过.
因此, 如果使用for循环能够减少剪切和粘贴错误.
For(int I = 0, n = list.size(); I<n; I++){
DoSomething(list.get(i);
}
变量n对性能是必须的, 不然每次循环都会执行一次size方法
规则 30 了解和使用类库
Collections.sort(v);
对Vector按字母顺序排序
Collections.sort(v, String.CASE_INSENSITIVE_ORDER);
System.out.println(Arrays.asList(a));
规则 32 避免字符串其他类型或许更合适
字符串不适合替代枚举类型, 类型安全枚举类型和int值都比字符串更适合用来表示枚举类型的常量.
字符串也不适合替代聚集类型,有一个更好的方法就是简单的写一个类来描述这个数据集,通常是一个私有的静态成员类最好。字符串也不适合代替能力表,总而言之,如果可以适合更加适合的数据类型,或者可以编写更加适当的数据类型,那么应该避免使用字符串来表示对象.
规则 33 注意string连接操作符的性能
重复的使用字符串连接操作符连接n个字符串需要n的平方的时间, 用连接字符串不适合规模较大的情况.
使用StringBuffer代替string存储字符串
public String statement(){
String s = “”;
For(int I = 0; I < numItems(); I++){
S += lineForItem(i);
}
}
public String statement(){
StringBuffer s = new StringBuffer(numItems()*LINE_WIDTH);
For(int I = 0; I<numItems(); I++){
s.append(lineForItem(i));
}
return s.toString();
}
规则 34 通过接口引用对象
如果你习惯用接口类型, 你的程序会更加灵活.
第八章 异常
规则 39 为异常情况使用异常
异常应该仅仅用在异常的情况下, 不能用来流程控制.
一个设计好的API不应该强制客户为控制流程使用异常
规则 40 为恢复条件检查异常, 为程序错误使用运行时异常
规则 41 避免使用不必要的异常检查
规则 42 使用标准异常
专家程序员和一般程序员的区别是专家高度的将代码复用
Effective Java word
access control 访问控制
accessibility 可访问能力,可访问性
accessor method 访问方法
adapter pattern 适配器模式
anonymous class 匿名类
antipattern 反模式
API Application Programming Interface,应用编程接口
API element API元素
array 数组
assertion 断言
binary compatibility 二进制兼容性
callback 回调
callback framework 回调框架
checked exception 被检查的异常
class 类
client 客户
comparator 比较器
composition 复合
concrete strategy 具体策略
constant interface 常量接口
copy constructor 拷贝构造函数
custom serialized form 自定义的序列化形式
decorator pattern decorator模式
default access 缺省访问
default constructor 缺省构造函数
defensive copy 保护性拷贝
delegation 委托
deserializing 反序列化
design pattern 设计模式
discriminated union 可区分的联合
doc comment 文档注释
documentation comment 文档注释
double-check idiom 双重检查模式
encapsulation 封装
enclosing instance 外围实例
enumerated type 可枚举的类型
exception 异常
exception chaining 异常链接
exception translation 异常转译
exported API 导出的API
extend 扩展
failure atomicity 失败原子性
field 域
finalizer guardian 终结函数守卫者
forwarding 转发
forwarding method 转发方法
function object 函数对象
function pointer 函数指针
general contract 通用约定
HTML validity checker HTML有效性检查器
idiom 习惯用法,模式
immutable 非可变的
implement 实现(用作动词)
implementation 实现(用作名词)
implementation inheritance 实现继承
information hiding 信息隐藏
inheritance 继承
inner class 内部类
integral constant 整值常量
interface 接口
interface inheritance 接口继承
Java Cryptography Extension Java密码子系统扩展,简称JCE
lazy initialization 迟缓初始化
local class 局部类
member 成员
member class 成员类
member interface 成员接口
memory footprint 内存印迹
memory model 内存模型
method 方法
mixin 混合类型
module 模块
mutator 改变对象属性的方法
naming convention 命名惯例
native method 本地方法
native object 本地对象
nested class 嵌套类
nonstatic member class 非静态的成员类
object 对象
object pool 对象池
object serialization 对象的序列化
obsolete reference 过期引用
open call 开放调用
overload 重载
override 改写
package-private 包-私有
performance model 性能模型
postcondition 后置条件
precondition 前提条件
precondition violation 前提违例
primitive 原语的,原语类型
private 私有的
public 公有的
redundant field 冗余域
reference type 引用类型
reflection 映像机制
register 注册
rounding mode 舍入模式
run-time exception 运行时刻异常
safe language 安全的语言
safety 安全性
semantic compatibility 语义兼容性
self-use 自用(性)
serial version UID 序列版本UID
serialized form 序列化形式
serializing 序列化
service provider framework 服务提供者框架
signature 原型
singleton pattern singleton模式
skeletal implementation 骨架实现
state transition 状态转变
static factory method 静态工厂方法
static member class 静态的成员类
storage pool 存储池
strategy interface 策略接口
strategy pattern 策略模式
stream unique identifier 流的唯一标识符
subclassing 子类化
summary description 概要描述
synthetic field 合成域
thread group 线程组
thread safety 线程安全性
thread-compatible 线程兼容的
thread-safe 线程安全的
top-level class 顶级类
typesafe enum class 类型安全的枚举类
typesafe enum pattern 类型安全的枚举模式
unchecked exception 未被检查的异常
unintentional object retention 无意识的对象保持
utility class 工具类
value class 值类
value type 值类型
view 视图
visitor pattern visitor模式
wrapper class 包装类