Java 多态性

Java 多态性

多态性是指一个对象可以以多种形式存在的能力。在面向对象编程中,最常见的多态性使用是在父类引用中引用子类对象。

任何可以通过多个IS-A测试的Java对象都被视为多态性的。在Java中,所有的Java对象都是多态的,因为任何对象都将通过其自身类型和类Object的IS-A测试。

需要知道的是,访问对象的唯一可能途径是通过引用变量。引用变量只能有一种类型。一旦声明,引用变量的类型就不能改变。

引用变量可以重新分配给其他对象,前提是它没有声明为final。引用变量的类型将确定它可以在对象上调用的方法。

引用变量可以引用其声明类型的任何对象或其子类型的任何对象。引用变量可以声明为类或接口类型。

示例

我们来看一个示例。

public interface Vegetarian{}
public class Animal{}
public class Deer extends Animal implements Vegetarian{}

现在,Deer类被视为多型的,因为它具有多重继承。对于上述示例,以下是正确的:

  • 一只Deer是一个动物。
  • 一只Deer是一个素食者。
  • 一只Deer是一只鹿。
  • 一只Deer是一个对象。

当我们将引用变量facts应用到一个Deer对象引用上时,以下声明是合法的:

示例

Deer d = new Deer();
Animal a = d;
Vegetarian v = d;
Object o = d;

所有的引用变量 d, a, v, o 都指向堆中的同一个 Deer 对象。

虚拟方法

在这一部分中,我将向您展示Java中重写方法的行为,这使您可以在设计类时利用多态性。

我们已经讨论过方法覆盖,其中子类可以覆盖父类中的方法。重写的方法实际上在父类中被隐藏,除非在重写的方法中子类使用super关键字来调用它。

示例

/* File name : Employee.java */
public class Employee {
   private String name;
   private String address;
   private int number;

   public Employee(String name, String address, int number) {
      System.out.println("Constructing an Employee");
      this.name = name;
      this.address = address;
      this.number = number;
   }

   public void mailCheck() {
      System.out.println("Mailing a check to " + this.name + " " + this.address);
   }

   public String toString() {
      return name + " " + address + " " + number;
   }

   public String getName() {
      return name;
   }

   public String getAddress() {
      return address;
   }

   public void setAddress(String newAddress) {
      address = newAddress;
   }

   public int getNumber() {
      return number;
   }
}

现在假设我们将Employee类扩展如下:

/* File name : Salary.java */
public class Salary extends Employee {
   private double salary; // Annual salary

   public Salary(String name, String address, int number, double salary) {
      super(name, address, number);
      setSalary(salary);
   }

   public void mailCheck() {
      System.out.println("Within mailCheck of Salary class ");
      System.out.println("Mailing check to " + getName()
      + " with salary " + salary);
   }

   public double getSalary() {
      return salary;
   }

   public void setSalary(double newSalary) {
      if(newSalary >= 0.0) {
         salary = newSalary;
      }
   }

   public double computePay() {
      System.out.println("Computing salary pay for " + getName());
      return salary/52;
   }
}

现在,你仔细研究以下程序,并尝试确定它的输出结果−

/* File name : VirtualDemo.java */
public class VirtualDemo {

   public static void main(String [] args) {
      Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
      Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
      System.out.println("Call mailCheck using Salary reference --");   
      s.mailCheck();
      System.out.println("\n Call mailCheck using Employee reference--");
      e.mailCheck();
   }
}

这将产生以下结果-

输出

Constructing an Employee
Constructing an Employee

Call mailCheck using Salary reference --
Within mailCheck of Salary class
Mailing check to Mohd Mohtashim with salary 3600.0

Call mailCheck using Employee reference--
Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.0

这里,我们实例化了两个Salary对象。一个使用Salary引用 s ,另一个使用Employee引用 e

在调用s.mailCheck()时,编译器在编译时看到Salary类中的mailCheck(),而JVM在运行时调用Salary类中的mailCheck()。

对于e.mailCheck()的mailCheck()来说是完全不同的,因为e是一个Employee引用。当编译器看到e.mailCheck()时,编译器看到了Employee类中的mailCheck()方法。

在这里,编译器在编译时使用了Employee的mailCheck()来验证这个语句。然而,在运行时,JVM调用的是Salary类中的mailCheck()。

这种行为被称为虚方法调用,这些方法被称为虚方法。一个被覆盖的方法在运行时被调用,无论在源代码中在编译时使用的是什么数据类型的引用。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程