父类、子类
利用继承可以基于已经存在的类(新类的父类)构造一个新类,新类会继承父类的方法和域,新类也可以添加新的方法和域,或覆盖新方法来覆盖父类的方法,以满足其需求。新类与父类之间存在“is-a”关系。类派生出来的所有类的集合被称为继承层次。从某个特定的类到期=其祖先的路径被称为该类的继承链。
定义子类
使用关键字extends,表明正在构造的新类派生于一个已存在的类。如下
public class Manager extends Employee{
添加方法和域;
}
调用父类的方法
super.getSalary();
调用父类的构造器
super(n,s,year,month,day); //调用父类中含有n,s,year,month,day参数的构造器,此语句要放在子类的最开头
super不是一个对象的引用,不能将super赋给另一个对象变量,它只是一个指示编译器调用父类方法的特殊关键字。
我们应该将通用的方法放在父类中,而将具有特殊用途的方法放在子类中
子类不能直接地访问父类的私有域,要访问父类的私有域,必须借助公有的接口。
子类不能删除继承的任何域和方法。
理解方法调用
- 编译器查看对象的声明类型和方法,至此编译器已获得所有可能被调用的候选方法
- 编译器将查看调用方法时提供的参数类型,至此编译器已获得需要调用方法名字和参数类型
- 如果是private、static、final或构造器方法,编译器就准确知道该调用哪些方法,调用的方法依赖隐式参数的实际类型,并且在运行时实现动态绑定(在运行时能够自动地选择调用哪个方法的现象称为动态绑定)。
- 当程序运行,并且采用动态绑定调用方法时,虚拟机一定调用与x所引用对象的实际类型最合适的那个类的方法。
- 每次调用方法都要进行搜索,时间开销大,因此,虚拟机预先为每个类创建了一个方法表,其中列出了所有方法的签名和实际调用的方法,这样一来,虚拟机调用方法的时候,仅查找这个表就行了。
阻止继承
final类和方法,其主要目的是确保他们不会在子类中改变语义。
不允许扩展的类被称为final类,final类中的所有方法自动成为final方法,不包括域,其声明如下:
public final class Executive extends Manager{
…
}
声明final方法,如下
public class Employee}
public final String getName(){
return name;
}
}
内联调用
如果一个方法没有被覆盖并且很短,编译器就能够对它进行优化处理,这个过程称为内联。
例如:
上面的e.getName就会被替换成为访问e.name域
抽象类
用abstract修饰符修饰,如果自下而上在类的继承层次结构中上移,位于上层的类更具有通用性,甚至可能更加抽象。为了提高程序的清晰度,包含一个或多个抽象方法的类本身必须被声明为抽象的,可以没有抽象方法。如下
public abstract class Person{
public abstract String getDescription();
}
- 抽象方法不能有方法体
- 抽象类不能被实例化
- 抽象类可以包含成员变量,方法(普通方法和抽象方法都可以),构造器,初始化块,内部类(接口、枚举)。抽象类的构造器不能创建该类实例,主要是为了让子类调用
- 当使用abstract修饰类时,表明这个类只能被继承;当使用abstract修饰方法时,表明这个方法必须由子类提供实现(重写)。而final修饰的类不能被继承,final修饰的方法也不能被重写,因此abstract和final不能同时使用
- abstract不能修饰成员变量,也不能修饰局部变量,以及构造器;
- abstract不能修饰类方法,即不能和static放在一起。
- abstract修饰的方法必须由子类重写才有意义,因此abstract不能和private同时修饰。
- 父类中可能包含需要调用其它系列方法的方法,这些被调方法即可以由父类实现,也可以由子类实现。父类提供的方法只是定义了一个通用算法,其实现也许并不完全由自身实现,而必须依赖其子类的辅助
多态
一个对象变量可以指示多种实际类型的现象称为多态。
“is-a”规则,表明子类的每个对象也是父类的对象;另一个表述法是置换法则,表明程序中出现父类对象的任何地方都可以用子类对象置换。
例如:将子类的对象赋给父类变量
Employee e;
e = new Employee(…);
a = new Manager(…);
例如:子类数组的引用可以转换成父类数组的引用
Manager[] managers = new Manager[10];
Employee[] staff = managers;
此文章内容来自java核心技术卷1