一、子类重定义父类成员
当子类从父类继承来的成员不能满足子类需要时,子类不能删除它们,但可以重定义它们,修改或扩充父类成员方法的功能,使父类成员能够适应子类新的需求。
重定义包括:
1、重定义父类的成员变量,则隐藏父类的成员变量
2、重定义父类的成员方法,如果参数列表和返回值类型均相同,则覆盖父类的成员方法;如果参数列表不同,则重载父类的成员方法。如果参数列表相同而返回值类型不同,编译器会指出存在二义性的语法错误。
子类重定义父类成员表现出多态性,父类对象引用父类成员,子类对象引用子类成员。重定义的同名成员之间不会产生冲突和混乱。在子类的实例方法中,可使用super引用访问被子类隐藏的父类同名成员变量,调用被子类覆盖的父类同名成员方法,语法格式如下:
super.成员变量
super.成员方法([参数列表])
super将当前对象作为其父类的一个实例引用。注意:静态方法中不能使用super引用
覆盖父类方法时,子类的访问权限不能小于父类方法的访问权限
二、类型的多态(Student类是Person类的子类)
1、子类对象即是父类对象,反之不然
对象运算符instanceof判断一个实例是否属于指定类
例如:new Person() instanceof Person //结果是true
2、父类对象引用子类实例,反之不行
Person p = new Student(); //赋值相容,子类对象即是父类对象
Student s = new Person(); //语法错,赋值不相容,父类对象不是子类对象
三、编译时多态和运行时多态
根据合适确定执行多态方法中的哪一个,多态分为两种情况:编译时多态和运行时多态。
1、编译时多态
方法重载都是编译时多态。
方法覆盖表现出两种多态性,当对象引用本类实例时,为编译时多态,否则为运行时多态。
2、运行时多态
当以下父类对象p引用子类实例时,p.toString()究竟执行的是谁的toString()方法?
Person p = new Student();
p.toString();
Java支持运行时多态,意为p.toString()实际执行p所引用实例的toString()方法,究竟执行Person类还是Student类的方法,运行时再确定。如果Student类声明toString()方法,则执行之,否则执行Person类的toString()方法
程序运行时,java从实例所属的类开始寻找匹配的方法执行,如果当前类中没有匹配方法,则沿着继承关系逐层向上,一次在父类或各祖先类中寻找匹配方法,直到object类。
因此,父类对象只能执行那些在父类中声明、被子类覆盖了的子类方法,如toString(),不能执行子类增加的成员方法。
多态的弊端:父类无法访问子类特有的属性和行为。因此在重写父类的方法时,形参仍然要是父类型的,但在方法体中可以向下转型。
例如:
Person类继承Object类,当重写equals方法时
public boolean equals(Object object) //注意,这里参数必须是Object,而不能是Student,因为如果是Student,那么就不是重写,而是重载
{
Person p = (Person) object ;
return this.name.equals(p.name);
}