- Java中提供了两种复用类的方法:组合和继承
- 组合:在新类中创建已有类的对象,即新类由现有类的对象所组成。只是复用了现有程序代码的功能,而非它的形式
- 继承:按照现有类来创建新类,无需改变现有类的形式,只需在其上添加新代码
- 继承时有下面的一般规则:将所有的数据成员指定为private,将所有的方法指定为public
- 调用基类构造器必须是你在导出类构造器中要考虑的第一件事
- 除了内存以外,不能依赖垃圾回收器去做任何事
- 如果需要进行清理,最好是编写自己的清理方法,但不要使用finalize()
- @overide注解关键字可以防止子类对基类方法的不必要重载
- 继承技术中最重要的方面是用来表现新类和基类之间的关系:新类是现有类的一种类型
- 继承可以确保基类中所有方法在导出类中也同样有效,所有能够向基类发送的所有消息也可以向导出类发送
- 将导出类引用转换为基类引用的动作称为“向上转型”
- 由导出类转型成基类,在继承图上是向上移动的,因此一般称为向上转型
- final修饰数据类型时用以向编译器告知一块数据是恒定不变的
- 在Java中,用final修饰的常量必须是基本数据类型,且在常量定义的时候应该对其进行赋值
- 如果用final修饰非基本类型,比如对象引用,则使对象引用恒定不变,而并不能保证所引用的对象不发生改变
- final方法可以明确禁止在子类中覆盖改方法
- 类中所有的private方法都隐式地指定为final的
- “覆盖”只有在某方法是基类的接口的一部分时才会出现
- 类的代码只会在初次使用时才加载
- 加载通常发生于创建类的第一个对象或者访问static域或者static方法时
- 初次使用之处也是static初始化发生之处
- 除非设计需要,否则尽量避免使用继承
关于初始化顺序的示例:
//The full process of initialization
class Insect
{
private int i = 9;
protected int j;
Insect()
{
System.out.println("i="+i+", j="+j);
j = 39;
}
private static int x1 = printInit("static Insect.x1 initialized");
static int printInit(String s)
{
System.out.println(s);
return 47;
}
}
public class Beetle extends Insect
{
private int k = printInit("Beetle.k initialized");
public Beetle()
{
System.out.println("k="+k+", j="+j);
}
private static int x2 = printInit("static Beetle.x2 initialized");
public static void main(String ... args)
{
System.out.println("Beetle Constructor");
Beetle b = new Beetle();
}
}
输出如下:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialzed
k = 47, j = 39
结果分析:
程序首先试图访问Beetle.main(),因为它是一个静态方法,从而引发Beetle类的加载(Beetle.class),编译器注意到它有一个基类,于是继续加载基类的编译代码,这一过程会持续下去,直到加载完根基类。由根基类向下到Beetle类中所有static域依次初始化。这段解释了输出结果中的前两行。之后才是类的创建过程。类构造器调用之前会首先对类中的数据域进行初始化,之后才是类构造器中的初始化。由于此例包含继承层级,这一初始化过程现在基类中发生,然后才轮到子类初始化。这段解释了输出结果中的后4行。