1. 判断什么时候该用继承,什么时候该用组合?
- 如果想利用新类内部一个现有类的特性,而不想使用它的接口,通常应选择合成。
- 为判断自己到底应该选用合成还是继承,一个最简单的办法就是考虑是否需要从新类上溯造型回基础类。若必须上溯,就需要继承。但如果不需要上溯造型,就应提醒自己防止继承的滥用。
2. 对final 关键字的理解
- 主要作用是:声明“某个东西不能改变”
- 应用场合:数据、方法和类。
2.1 final数据:
将数据变为常数
修饰形参时,主要为匿名内部类传递数据。
(1) 编译期常数,它永远不会改变(可节约运行期的一些开销)
(2) 在运行期初始化的一个值,我们不希望它发生变化 - 一个很好的例子:
class Value {
int i = 1;
}
public class FinalData {
// Can be compile-time constants
final int i1 = 9;
static final int I2 = 99;
// Typical public constant:
public static final int I3 = 39;
// Cannot be compile-time constants:
final int i4 = (int)(Math.random()*20);
static final int i5 = (int)(Math.random()*20);
Value v1 = new Value();
final Value v2 = new Value();
static final Value v3 = new Value();
//! final Value v4; // Pre-Java 1.1 Error:
// no initializer
// Arrays:
final int[] a = { 1, 2, 3, 4, 5, 6 };
public void print(String id) {
System.out.println(
id + ": " + "i4 = " + i4 +", i5 = " + i5);
}
public static void main(String[] args) {
FinalData fd1 = new FinalData();
//! fd1.i1++; // Error: can't change value
fd1.v2.i++; // Object isn't constant!
fd1.v1 = new Value(); // OK -- not final
for(int i = 0; i < fd1.a.length; i++)
fd1.a[i]++; // Object isn't constant!
//! fd1.v2 = new Value(); // Error: Can't
//! fd1.v3 = new Value(); // change handle
//! fd1.a = new int[3];
fd1.print("fd1");
System.out.println("Creating new FinalData");
FinalData fd2 = new FinalData();
fd1.print("fd1");
fd2.print("fd2");
}
} ///:~
out(输出):
fd1: i4 = 2, i5 = 3
Creating new FinalData
fd1: i4 = 2, i5 = 3
fd2: i4 = 16, i5 = 3
i4和i5向大家证明了:
1. 当值在运行期间初始化时,没有被static修饰的final数据的值在不同对象之间是不同的
2. 不能由于某样东西的属性是final,就认定它的值能在编译时期知道
一个很重要的结论:static强调只有一个,即多个对象共享的,final表明它是一个常数
- 一些不常见的结论:
1. 类中所有private方法都隐式地指定为final的。
2. 构造器也是static方法,虽然static关键字没有显示地写出来。
3. 类是在其任何static成员被访问时加载的。
4. Java中除了static方法和final方法(private方法属于final方法)是前期绑定之外,其他所有的方法都是后期绑定(也叫运行时绑定或动态绑定),这也解释了多态中接收基类类型的引用却能够在运行时正确调用子类方法这一奇怪行为。
5. 将某一个方法声明为final可以关闭动态绑定,因此可以提高一丢丢性能,不过基本可以忽略不计。