JAVA多态-重写、重载与虚方法
JAVA多态-重写、重载与虚方法
1. 重写(Override)
子类对父类的方法进行重写, 返回值和形参都不能改变
class Animal{
public void move(){
System.out.println("动物可以移动");
}
}
class Dog extends Animal{
public void move(){
System.out.println("狗可以跑和走");
}
}
public class TestDog{
public static void main(String args[]){
Animal animal = new Animal(); // Animal 对象
Animal dog = new Dog(); // Dog 对象
animal.move();// 执行 Animal 类的方法
dog.move();//执行 Dog 类的方法
}
}
运行结果如下:
动物可以移动
狗可以跑和走
重写规则
- 参数列表与被重写方法的参数列表必须完全相同。
- 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
- 父类的成员方法只能被它的子类重写。
- 声明为 final 的方法不能被重写。
- 声明为 static 的方法不能被重写,但是能够被再次声明。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 构造方法不能被重写。
- 如果不能继承一个类,则不能重写该类的方法。
2. 重载(Overloading)
是在一个类里面,方法名字相同,必须参数不同。返回类型可以相同也可以不同。
最常用的地方就是构造器的重载。
3. 重写与重载之间的区别
区别点 | 重载方法 | 重写方法 |
---|---|---|
参数列表 | 必须修改 | 一定不能修改 |
返回类型 | 可以修改 | 一定不能修改 |
异常 | 可以修改 | 可以减少或删除,一定不能抛出新的或者更广的异常 |
访问 | 可以修改 | 一定不能做更严格的限制(可以降低限制) |
- 重载是一个类的多态性表现
- 重写是子类与父类的一种多态性表现
4. 多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象:Parent p = new Child();
- 使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
虚方法
虚函数的存在是为了多态。
- 在编译的时候,编译器使用 父类Parent 中的 method() 方法验证该语句, 但是在运行的时候,Java虚拟机(JVM)调用的是 子类Sub 中的 method() 方法。
以上整个过程被称为虚方法调用,该方法被称为虚方法。
Java中所有的方法都能以这种方式表现,因此,重写的方法能在运行时调用,不管编译的时候源代码中引用变量是什么数据类型。
5. 虚函数的具体解释:抽象方法、抽象类与接口
C++: 虚函数 纯虚函数
java: 普通函数 抽象函数
java 普通函数就相当于c++ 中的虚函数,c++中非virtual方法不能被子类重写
Java抽象函数 abstract Function(纯虚函数)
抽象函数或者说是纯虚函数的存在是为了定义接口。
C++中纯虚函数形式为:virtual void print() = 0;
Java中纯虚函数形式为:abstract void print();
PS: 在抽象函数方面C++和Java还是换汤不换药。
Java抽象类 abstract Class
抽象类中可以有数据成员和非抽象方法,也包括需要子类各自实现的函数接口;
C++中抽象类只需要包括纯虚函数,既是一个抽象类。如果仅仅包括虚函数,不能定义为抽象类,因为类中其实没有抽象的概念。
PS: 抽象类其实是一个半虚半实的东西,可以全部为虚,这时候变成接口(接口中只能有static, abstract 和default方法)
接口与抽象类
一个类可以实现(implements)多个接口。一个类只能继承(extends)一个抽象类。
接口没有构造函数,所有方法都是 public abstract的,一般不定义成员变量。(所有的成员变量都是 static final ,而且必须显示初始化)。 抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
一个实现接口的类,必须实现接口内所描述的所有方法(所有方法都是抽象的方法),否则就必须声明为抽象类。