3. 類和接口
類和接口是Java編程的核心
Item13 最小化類和成員變量的訪問權限
信息隱藏與封裝是程序設計的基本原則
通用經(jīng)驗是能讓類或者變量不可訪問就讓它不可訪問
四種訪問權限:
- private
只在它聲明的地方可用 - package-private
同一個包內可用 - protected
同一個包或子類可用 - public
任何地方可用
公共類不應包含公共字段。確保static final引用的對象是不可變的每窖。
絕不可以用private static final來聲明一個數(shù)組對象
Item14 用公共方法提供公共字段
//bad
public class Point {
public int x;
public int y;
}
//good
class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() { return x; }
public double getY() { return y; }
public void setX(double x) { this.x = x; }
public void setY(double y) { this.y = y; }
}
Item15 最小化可變性
對象始終不變的類比可變的更安全和好用,如String
我們設計不可變對象時應遵循如下準則:
- 不要提供任何方法來改變對象的狀態(tài)
- 確保類不可繼承
- 所有的字段使用private final修飾
- 確保不要讓類中的可變對象訪問,使用深拷貝替代
如果一個類確實可變,也要保證其它地方盡可能不變,TimerTask是很好的例子
Item16 組合和繼承,優(yōu)先使用組合
繼承雖然有很多好處,但是違背了封裝性,暴露了父類的實現(xiàn)細節(jié)
Item17 專用于繼承的設計趁仙,否則禁止繼承
未能理解,后續(xù)補充
Item18 接口和抽象類之間傾向于接口
Java提供了兩種機制來提供多個類型定義的實現(xiàn):接口和抽象類
最明顯的區(qū)別在于抽象類允許某些方法的實現(xiàn),更重要的區(qū)別在于一個類使用了抽象類的方式來定義,則這個類必須是抽象類的子類.因為Java只允許單一繼承亲澡,因此對抽象類的這種限制嚴重影響了它們作為類型定義的使用
- 已經(jīng)存在的類可以很容易的實現(xiàn)一個新的接口
比如實現(xiàn)Comparable接口 - 接口是定義混合器的理想選擇
比如為一個主要類型的類添加比較方法,可通過實現(xiàn)Comparable接口實現(xiàn)實例之間的排序
有一個特例是抽象類比接口更加易用,如果注重程序的易用性而不是靈活性則可以考慮抽象類
Item19 僅使用接口定義類型
當一個類實現(xiàn)了一個接口,這個接口是為類的實例服務的而不是為了其他目的
所以有一種常量接口盡量不要使用
//bad
public interface PhysicalConstants {
// Avogadro's number (1/mol)
static final double AVOGADROS_NUMBER = 6.02214199e23;
// Boltzmann constant (J/K)
static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
// Mass of the electron (kg)
static final double ELECTRON_MASS = 9.10938188e-31;
}
如果有這種常量需要使用,可以把它定義在與之關聯(lián)的類里面
Item20 用繼承來替代復合類(原單詞: tagged classes)
偶爾會遇到一個類的實例包含了多種不同的類別,如下
// bad 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();
}
}
}
優(yōu)化如下
//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; }
}
Item21 使用函數(shù)對象表示策略
直譯過來有點不好理解,大意是對于多個類都要使用的策略(或用方法表示),采用接口來實現(xiàn)
如一個類需要比較方法,另一個類也需要,則抽象出一個Comparable接口來給各個類通用
Item22 嵌套類的使用
有四種嵌套類,分別是靜態(tài)成員類灶搜、非靜態(tài)成員類、匿名內部類和本地類
除了第一個都是內部類
- 靜態(tài)成員類
可以訪問外部類的私有屬性 - 非靜態(tài)成員類
同靜態(tài)成員類,區(qū)別在于沒有static修飾
public class MySet<E> extends AbstractSet<E> {
public Iterator<E> iterator() {
return new MyIterator();
}
//典型用法
private class MyIterator implements Iterator<E> {
...
}
}
- 匿名內部類
不用聲明,常用于監(jiān)聽器,隨用隨銷 - 本地類
略 未能理解,后續(xù)補充,歡迎留言增益知識
如果成員類需要外部類的引用,則使用非靜態(tài)成員類,否則使用靜態(tài)成員類