继承的概念
- 继承(inheritance)是面向对象的重要概念之一,它提供在已有类的基础上创建新类,使新创建的类自动拥有被继承类的全部成员;是构造可复用软件的有效机制。
父类/超类——被继承类;
子类/派生类——继承产生的新类。
① 子类自动拥有父类的全部成员,包括成员变量和方法等;
② 子类可以更改从父类继承来的成员,使成员适应新的需求;
③ 子类也可以增加自己的成员,使类的功能得以扩充;
④ 但是,子类不能删除父类的成员。
注:Java中仅仅支持单一继承(即子类只能继承一个父类),同时Java采用Interface(接口)变相实现多重继承而避免父类二义性。
继承的语法
在Java中实现继承需要使用到extends关键字。
实现继承的一般语法是:
[访问修饰符] class 派生类名 extends 基类名 {
成员列表
}
如:
class Student extends Person
{
//实现Student类的数据成员和成员方法
}
子类对象实例化过程
① 先调用父类的构造->调用父类构造函数;
② 再调用子类构造->调用子类构造函数;
③ 若子类中没有定义构造方法,则它自动地调用父类无参数的构造方法;若子类定义了构造方法,应该在第一条语句的位置调用父类的构造方法,否则系统将在此位置插入一条调用父类无参数构造方法的语句;
④ 对于父类中含有参数的构造方法,只能在子类的构造方法中利用super显式地调用。
如:
class Person {
public Person(){
System.out.println("父类Person的构造方法");
}
}
class Student extends Person{
public Student(){
System.out.println("子类student构造方法");
}
}
public class testExtend {
public static void main(String args[]){
Student stu = new Student();
}
}
输出:
父类Person的构造方法
子类student的构造
注:
- 如果父类成员方法为private,则不能在子类用super.调用;
- 子类可定义父类名字类型限定符都相同的属性,不能重写与父类名字相同而限定符不同的方法;
- 父类引用不能调用子类新扩展的成员方法。
重要结论:
父类对象引用子类实例
如 :Person p = new Student();
子类对象不能引用父类实例
如Student s = new Person(); // 是错误的;
- 如果使用父类对象引用子类实例,父类对象只能执行那些在父类中声明、被子类覆盖了的子类方法。
Java的多态
多态性 (Polymorphism) 是指一个程序中同名的不同方法共存的情况,即一个程序中相同名字方法表示不同的实现
- 表现在继承中→方法的重写(overwrite)
- 表现在一个类中→方法的重载(override/overload)
Java多态的类型
编译时多态性
对于多个同名方法,如果在编译时能够确定执行同名方法中的哪一个,则称为编译时多态性。
运行时多态性
如果在编译时不能确定、只有在运行时才能确定执行多个同名方法中的哪一个,则称为运行时多态。
方法的重载——都是编译时多态性;
方法的覆盖——表现出两种多态性,当对象引用本类实例时,为编译时多态性;否则为运行时多态性。
子类重写父类成员方法
当子类从父类继承来的成员不能满足子类需要时,子类不能删除它们,但可以重定义它们,扩充父类成员方法的功能,使父类成员能够适应子类新的需求。
子类重定义父类成员包括:
①重定义父类的成员变量,则隐藏父类的成员变量;
②重定义父类的成员方法,如果参数列表相同,则覆盖父类的成员方法,否则重载。
抽象方法与抽象类
抽象方法—用于声明方法的参数和返回值,具体实现由抽象类的子类完成,子类必须覆盖父类的抽象方法。
- 抽象方法是一种特殊的方法,它只有声明而没有具体的实现,抽象方法必须用abstract关键字进行修饰;
- 如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。
抽象类—用于描述抽象的概念,其中声明的抽象方法为多个子类约定方法声明,每个子类可以根据自身的实际情况,给出抽象方法的具体实现,显然不同的子类可以有不同的方法实。
- 抽象类中可以有零个或多个抽象方法,也可以包含非抽象的方法。抽象类中可以没有抽象方法,有抽象方法的类必须是抽象类;
- 抽象类可以派生子类,在抽象类派生的子类中必须实现抽象类中定义的所有抽象方法。
- 抽象类不能创建对象,创建对象的工作由抽象类派生的子类来实现。
- 如果父类已有同名的abstract方法,则子类中就不能再有同名的抽象方法。
- abstract**不能与final并列修饰同一个类; 不能**与private、static、final或native并列修饰同一个方法。
Java类的接口
前面讲到在Java中只能单一继承,而接口可以实现类间多继承结构。接口内部只能定义 public 的抽象方法和公有的、静态常量,因此接口中的所有方法都需要在子类中实。
接口的定义
[public] interface 接口名称
{
常量;//默认public static final
方法;//默认public abstract
}
注:在定义接口时,若没有public,则该接口只能由同一个包中的类或接口引用。
接口的实现
[访问修饰符] class 类名 implements[接口列表]
{
public 成员函数;
}
例子:
interface A
{
double g=9.8;//g只能是public static final的常量
void show();//这个方法也只能是public abstract的
}
class B implements A
{
public void show()
{
System.out.println("g="+g);
}
}
class InterfaceTest{
public static void main(String args[])
{
B b=new B();
b.show();
A a=new B();
a.show();
}
}
结果:
g=9.8
g=9.8
接口的注意事项
- 一个类可以继承多个接口,但必须实现每个口的全部成员方法,若不实现全部成员方法,则必须将该类说明成abstract;
- 使用接口的好处是统一操作接口,即可以在不暴露具体类的前提下,公开操作接口的规范。