《Effective Java》读书笔记三(类和接口)
No13 使类和成员的可访问性最小化
要区别设计良好的模块与设计不好的模块,最重要的因素在于,这个模块对于外部的其他模块而言,是否隐藏其内部数据和其他实现细节。模块之间只通过它们的API进行通信,一个模块不需要知道其他模块的内部工作情况。这个概念被称为信息隐藏(infomation hiding)或封装(encapsulation),是软件设计的基本原则之一。
对于顶层的(非嵌套的)类和接口,只有两种可能的访问级别:
- 包级别的(package-private)。
- 公有的(public)。
对于成员(域、方法、嵌套类和嵌套接口)有四种可能的访问级别:
- 私有的(private)。
- 包级私有的(package-private),缺省default访问级别。
- 受保护的(protected)。
- 公有的(public)。
实例域决不能是公有的。同样的建议也适用于静态域(常量例外)。
安全漏洞之一:
// Potential security hole!
public static final Thing[] VALUES = {...};
注意:引用本身不能被修改,但是它所引用的对象却可以被修改—这会导致灾难性的后果。
建议:
private static final Thing[] PRIVATE_VALUES = {...};
public static final Thing[] values() {
return PRIVATE_VALUES.clone();
}
No16 复合(composition)优先于继承(inheritance)
对普通的具体类(concrete class)进行跨越包边界的继承,是非常危险的,特指当一个类扩展另一个类的时候(不考虑同一程序员的情况,也不考虑专门为继承而设计的类的情况)。主要原因是因为继承可能导致不确定的风险,需要你深入了解父类细节。
与方法调用不同的是,继承打破了封装性。换句话说,子类依赖于其超类中特定功能的实现细节。超类的实现有可能会随着发行版本的不同而有所变化。
只有当子类和超类之间确实存在子类型关系时,使用继承才是恰当的。换句话说,对于两个类A和B,只有当两者之间确实存在“is-a”关系的时候,类B才应该扩展类A;否则类B就不应该扩展类A,而是让B包含A的一个私有实例。
No20 类层次优于标签类
考虑下面这个类,它能够表示圆形或者矩形:
// Tagged class - vastly inferior to a class hierarchy!
class Figure {
enum Shape { RECTANGLE, CIRCLE }; // Tag field - the shape of this figure
final Shape shape; // These fields are used only if shape is RECTANGLE
double length;
double width; // This field is used only if shape is CIRCLE
double radius; // Constructor for circle
Figure(double radius) {
shape = Shape.CIRCLE;
this.radius = radius;
} // Constructor for rectangle
Figure(double length, double width) {
shape = Shape.RECTANGLE;
this.length = length;
this.width = width;
} double area() {
switch(shape) {
case RECTANGLE:
return length * width;
case CIRCLE:
return Math.PI * (radius * radius);
default:
throw new AssertionError();
}
}
}
这种标签类(tagged class)有着许多缺点。它们中充斥着样板代码,包括枚举声明,标签域以及条件语句,破坏了可读性。
我们再看看下面的代码:
// Class hierarchy replacement for a tagged class
abstract class Figure {
abstract double area();
}
class Circle extends Figure {
final double radius;
Circle(double radius) { this.radius = radius; }
double area() { return Math.PI * (radius * radius); }
}
class Rectangle extends Figure {
final double length;
final double width;
Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
double area() { return length * width; }
}
这个类层次纠正了前面提到过的标签类的所有缺点。代码简单且清楚。另一种好处,有助于增强灵活性,比如扩展一个正方形,只需要扩展长方形即可:
class Square extends Rectangle {
Square(double side) {
super(side, side);
}
}
No22 优先考虑静态成员类
嵌套类(nested class)是指被定义在另一个类的内部的类。嵌套类存在的目的应该只是为它的外围类(enclosing class)提供服务。如果嵌套类将来可能会用于其他的某个环境中,它就应该是顶层类(top-level class)。
嵌套类有四种:静态成员类(static member class)、非静态成员类(nonstatic member class)、匿名类(anonymous class)和局部类(local class)。除了第一种以外,其他三种被称为内部类(inner class)。
静态成员类是最简单的一种嵌套类。最好把它看作是普通的类,只是碰巧被声明在另一个类的内部而已,它可以访问外围类的所有成员,包括那些被声明为私有的成员。静态成员类是外围类的一个静态成员,与其他的静态成员末端,也遵守同样的可访问性规则。如果它被声明为私有的,它就只能在外围类的内部才可以访问。
静态成员类的一种常见用法是作为公有的辅助类,仅当它与它的外部类一起使用时才意义。
非静态成员类的一种常见用法是定义一个Adapter,它允许外部类的实例被看作是另一个不相关的类的实例。示范:
// Typical use of a nonstatic member class
public class MySet<E> extends AbstractSet<E> {
// Bulk of the class omitted public Iterator<E> iterator() {
return new MyIterator();
} private class MyIterator implements Iterator<E> {
// ...
}
}
如果成员类的每个实例都需要一个指向其外围实例的引用,就要把成员类做成非静态的;否则,就做成静态的。
匿名类可以出现在代码中任何允许存在表达式的地方。由于匿名类出现出现在表达式当中,它们必须保持简短—大约10行或者更少些—否则会影响程序的可读性。
匿名类的一种常见用法是动态地创建函数对象,例如:
Arrays.sort(stringArray, new Comparator<String>(){
public int compare(String s1, String s2) {
return s1.length() – s2.length();
}});
局部类是四种嵌套类中用得最少的类。在任何“可以声明局部变量”的地方,都可以声明局部类,并且局部类也遵守同样的作用域规则。
《Effective Java》读书笔记三(类和接口)的更多相关文章
- Effective Java 读书笔记之三 类和接口
一.使类和成员的可访问性最小化 1.尽可能地使每个类或者成员不被外界访问. 2.实例域决不能是共有的.包含公有可变域的类不是线程安全的. 3.除了公有静态final域的特殊情形之外,公有类都不应该包含 ...
- 《Effective Java》读书笔记 - 4.类和接口
Chapter 4 Classes and Interfaces Item 13: Minimize the accessibility of classes and members 一个好的模块设计 ...
- Effective Java读书笔记--类和接口
1.使类和成员的可访问性最小化不指定访问级别,就是包私有.protected = 包私有 + 子类一般private不会被访问到,如果实现了Serializable,可能会泄露.反射.final集合或 ...
- Effective java读书笔记
2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.J ...
- Effective Java读书笔记完结啦
Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...
- [Effective Java]第四章 类和接口
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- Effective Java 读书笔记之五 枚举和注解
Java1.5中引入了两个新的应用类型家族,新的类为枚举类型,新的接口为注解类型. 一.用enum代替int常量 1.枚举值由一组固定的常量组成合法值的类型. 二.用实例域代替序数 1.不要根据枚举的 ...
- 《Effective Java》笔记 使类和成员的可访问性最小化
类和接口 第13条 使类和成员的可访问性最小化 1.设计良好的模块会隐藏所有的实现细节,把它的API与实现清晰的隔离开来,模块之间只通过它们的API进行通信,一个模块不需要知道其他模块的内部工作情况: ...
- 初读"Thinking in Java"读书笔记之第九章 --- 接口
抽象类和抽象方法 abstract void f();抽象方法是仅有声明而没有方法体的方法. 包含抽象方法的类叫做抽象类,如果一个类包含了一个抽象方法,则该类必须限定为抽象类. 抽象类和抽象方法可以使 ...
- Effective Java 读书笔记(一):使用静态工厂方法代替构造器
这是Effective Java第2章提出的第一条建议: 考虑用静态工厂方法代替构造器 此处的静态工厂方法并不是设计模式,主要指static修饰的静态方法,关于static的说明可以参考之前的博文&l ...
随机推荐
- hdu1874 畅通project续(求最短路径)
畅通project续 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- Effective C++:条款26:尽可能延后变量定义式的出现时间
(一) 那么当程序的控制流到达这个变量定义时.变承受构造成本:当变量离开作用域时.便承受析构成本. string encryptPassword(const std::string& pass ...
- Android之新建项目
最近开始接触Android,实践出真理,接下来实际创建Android应用程序. 1.启动Eclipse,依次选择 " File/New/Project... " 或 " ...
- 去除icon图标特效,阴影,反光
在icon默认情况: 程序的图标会被apple进行美化, 自动圆角, 加上阴影和反光效果:如果不想要这种效果:在Info.plist中 添加一个Icon already includes gloss ...
- H面试(23):求子数组最大和
题目描述: 输入一个整形数组,数组里有正数也有负数. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 求所有子数组的和的最大值.要求时间复杂度为O(n). 例如输入的数组为1, -2 ...
- php之快速入门学习-18(PHP 面向对象)
PHP 面向对象 在面向对象的程序设计(英语:Object-oriented programming,缩写:OOP)中,对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象. 在现实 ...
- 优化后队列的实现(C语言实现)
上一篇中的队列的定义与实现(C语言实现) 中.不管是顺序队列还是链式队列,在尾加和删除头部的操作时.总有一个时间复杂度让人不惬意. 比方在顺序队列中,删除头部的操作后,总要将后面全部的结点都向前移动一 ...
- 数制转换-栈的应用(C++实现)
本程序实现的是十进制与不同进制之间的的数据转换,利用的数据结构是栈,基本数学方法辗转相除法. conversion.h #include<stack> using namespace st ...
- c语言转移符和三字母序列
三字母序列
- jQuery写一个简单的弹幕墙
概述 近几年由于直播,弹幕流行起来,之前看到过用js制作弹幕墙的思路,觉得很有趣.自己就花了点时间把他做成了更灵活的jQuery插件,现在分享出来. 详细 代码下载:http://www.demoda ...