继承与多态
类的继承
被继承的类称为父类或超类,继承得到的类称为子类或派生类。
public class SubClass extends SuperClass{
//类体定义
}
几点说明
-
子类继承父类中非private的成员变量和成员方法。
-
父类中定义的private成员变量和方法不能被子类继承,因此在子类中不能直接使用。如果父类中定义了公共的访问方法和修改方法,子类可以通过这些方法访问或修改它们。
-
final修饰符修饰的类不能被继承。
-
定义类时若缺省extends关键字,则所定义的类为java.lang.Object类的直接子类。
-
java仅支持单重继承,即一个类至多只有一个直接父类。(在java中可以通过接口实现其他语言的多重继承)
方法覆盖
在子类中定义与父类中的名字、参数列表、返回值类型都相同的方法,这时子类的方法就叫作覆盖或重写了父类的方法。
@Override
public String toString(){
return "姓名:"+name;
}
@Override注解表示其后的方法必须是覆盖父类的一个方法,可避免编写错误。
两点注意
-
private方法不能覆盖
-
父类中的static方法可以被继承,但不能被覆盖。如果子类中定义了与父类中的static方法完全一样的方法,那么父类中的方法被隐藏。父类中被隐藏的static方法仍然可以使用“类名.方法名()”形式调用。
-
final修饰的方法不能被子类覆盖,否则会发生编译错误。
方法重载与方法覆盖
方法重载是在一个类中定义多个名称相同但参数不同的方法。方法覆盖实在子类中为父类中的同名方法提供一个不同的实现。
super关键字
(1)在子类中调用父类中被覆盖的方法
super.methodName([paramlist])
(2)在子类中调用父类的构造方法
super([paramlist])
不能用super调用间接父类的构造方法,如super.super()是不合法的。
在任何情况下,创建一个类的实例时,将会沿着继承链调用所有父类的构造方法。
//定义父类
public class Vehicle{
public Vehicle(){
System.out.println("创建Vehicle对象");
}
}
//子类
public class Bicycle extends Vehicle{
public Bycicle(){
System.out.println("创建Bycicle对象");
}
public static void main(String[] args){
Bycicle mybycicle = new Bycicle;
}
}
//运行结果
//创建Vehicle对象
//创建Bycicle对象
(3)在子类中访问父类中被隐藏的成员变量
super.variableName
methodName:父类中被覆盖的方法名
paramlist:方法传递的参数
variableName:父类中被隐藏的变量名
封装性与访问修饰符
实现封装的两种方式:
(1)通过包实现封装性。包是Java语言最大的封装单位。
(2)通过类或类的成员访问权限实现封装性。
类成员的访问权限
(1)private:私有成员,只能被这个类本身访问,外界不能访问。
(2)缺省访问修饰符:一般称为包可访问的。可以被该类本身和同一个包中的类访问,其他包中的类不能访问这些成员。
(3)protected:保护成员。可被这个类本身、同一个包中的类以及该类的子类(包括同一个包以及不同包中的子类)访问。
(4)public:公共成员。可以被任何其他的类访问。
抽象类(abstract)
public abstract class Shape{
String name;
public Shape(){} //抽象类可以定义构造方法
public Shape(String name){
this.name=name;
}
public abstract double getArea(); //定义抽象方法
}
-
抽象方法:只有方法的声明,没有方法的实现。作用为所有子类提供一个统一的接口。
-
包含抽象方法的类必须定义为抽象类。抽象类中可以定义非抽象的方法。
-
抽象类中可以定义构造方法,这些构造方法可以在子类中调用。
-
抽象类不能被实例化,即不能生成抽象类的对象。
Shape sh = new Shape();//发生编译错误,抽象类不能实例化
-
抽象类的子类还可以是抽象类,只有非抽象的子类才能使用new创建该类的对象。
-
抽象类必须被子类继承,才能实例化。
对象转换
(子类对象和父类对象在一定条件下可以相互转换)
自动转换(向上转换)
子类是父类的特殊化,每个子类的实例也都是它父类的实例。
子类对象可以作为父类对象使用,即子类对象可以自动转换为父类对象,将子类型的引用赋值给父类型的引用。
parent = child; //子类对象自动转换为父类对象,parent为父类型引用,child为子类型引用
强制转换(向下转换)
通过()。
Employee emp = new Employee("lihua");
Person p = emp;
emp = (Employee)p; //emp子类对象,p父类对象
父类对象转换为子类对象,必须要求父类对象是用子类构造方法生成的。
Person p = new Person();
Employee emp = (Employee)p;//不能强制转换
当将一个子类型引用转换为一个父类型引用时,使用该引用可以调用父类型中定义的方法,但看不到子类型中定义的方法。
instanceof运算符
测试一个实例是否是某种类型的实例。
variable instanceof TypeName
Fruit fruit = new Apple();
//Fruit:父类 Apple:子类
//表达式fruit instanceof Fruit的结果为true.
多态与动态绑定
(1)静态多态:也叫编译时多态,是通过方法重载实现的。
(2)动态多态:也叫运行时多态,是通过方法覆盖实现的。
方法绑定:将方法调用与方法体关联起来。
动态绑定:在程序运行时根据对象的类型进行绑定。