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 ,而且必须显示初始化)。 抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。

一个实现接口的类,必须实现接口内所描述的所有方法(所有方法都是抽象的方法),否则就必须声明为抽象类。