Polymorphism(多态)

本文深入探讨了Java中多态的概念及其实现方式。通过具体示例介绍了如何利用父类引用指向子类对象来体现多态性,并展示了方法重写如何在运行时决定调用哪个版本的方法,以此实现多态行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    一篇关于多态的好文,出处:http://www.tutorialspoint.com/java/java_polymorphism.htm

    Polymorphism is the ability of an object to take on many forms. The most common use of polymorphism in OOP occurs when a parent class reference is used to refer to a child class object.

Any java object that can pass more than on IS-A test is considered to be polymorphic. In Java, all java objects are polymorphic since any object will pass the IS-A test for their own type and for the class Object.

It is important to know that the only possible way to access an object is through a reference variable. A reference variable can be of only one type. Once declared the type of a reference variable cannot be changed.

The reference variable can be reassigned to other objects provided that it is not declared final. The type of the reference variable would determine the methods that it can invoke on the object.

A reference variable can refer to any object of its declared type or any subtype of its declared type. A reference variable can be declared as a class or interface type.

Example:

Let us look at an example.

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

Now the Deer class is considered to be polymorphic since this has multiple inheritance. Following are true for the above example:

  • A Deer IS-A aAnimal

  • A Deer IS-A Vegetarian

  • A Deer IS-A Deer

  • A Deer IS-A Object

When we apply the reference variable facts to a Deer object reference, the following declarations are legal:

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

All the reference variables d,a,v,o refer to the same Deer object in the heap.

Virtual Methods:

In this section, I will show you how the behavior of overridden methods in Java allows you to take advantage of polymorphism when designing your classes.

We already have discussed method overriding, where a child class can override a method in its parent. An overridden method is essentially hidden in the parent class, and is not invoked unless the child class uses the super keyword within the overriding method.

/* 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;
  }
}

Now suppose we extend Employee class as follows:

/* 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;
   }
}

Now you study the following program carefully and try to determine its output:

/* 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();
    }
}

This would produce following result:

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

Here we instantiate two Salary objects . one using a Salary reference s, and the other using an Employee reference e.

While invoking s.mailCheck() the compiler sees mailCheck() in the Salary class at compile time, and the JVM invokes mailCheck() in the Salary class at run time.

Invoking mailCheck() on e is quite different because e is an Employee reference. When the compiler seese.mailCheck(), the compiler sees the mailCheck() method in the Employee class.

Here, at compile time, the compiler used mailCheck() in Employee to validate this statement. At run time, however, the JVM invokes mailCheck() in the Salary class.

This behavior is referred to as virtual method invocation, and the methods are referred to as virtual methods. All methods in Java behave in this manner, whereby an overridden method is invoked at run time, no matter what data type the reference is that was used in the source code at compile time.

06-06
<think>首先,用户的问题是:“我想了解多态的概念或用法请问多态在编程中的实现和应用”,这是关于多态的概念、实现和应用。根据系统级指令:-所有行内数学表达式必须使用$...$格式。-独立公式必须使用$$...$$格式并单独成段。-LaTeX语法正确。-使用中文回答。-生成相关问题。-回答中引用的段落末尾自然地添加引用标识,例如:[^1]在参考内容中,有多个引用:-引用[^1]:关于什么是多态和它的应用场景。-引用[^2]:关于多态的实现和应用。-引用[^3]:关于Java中多态的概念、实现原理。-引用[^4]:一个Java多态编程实例。用户说这些引用仅供参考,不是用户真正的需求,但要参考用户上一次的问题和我的回答。用户上一次的问题似乎是在之前,但在这个对话框中,用户上一次的问题是:“参考站内引用:引用[1]:...”,但实际上用户的问题是“我想了解多态的概念或用法请问多态在编程中的实现和应用”。在历史中,用户没有提供上一次问题和回答。在系统提示中说:“请尽可能多的参考用户上一次的问题和你的回答”,但在这个特定对话中,这是第一个用户消息?回顾:用户消息是以“参考站内引用...”开始的,这似乎是用户在提供引用。用户消息是:“参考站内引用:引用[1]:......上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。我想了解多态的概念或用法请问多态在编程中的实现和应用”所以,用户现在的问题是:“我想了解多态的概念或用法请问多态在编程中的实现和应用”,并说参考站内引用,但不是用户真正的需求,要参考上一次的问题和回答。但在这个对话线程中,这是我与用户的第一次交互。所以,可能没有“上一次的问题和回答”。我应该基于当前用户的需求来处理。核心需求:用户想知道多态的概念、实现和应用。结构化回答:1.概念:解释多态是什么。2.实现:如何实现多态(例如,在面向对象编程中通过继承和接口)。3.应用:应用场景(如例子中提到)。使用中文回答。在回答中,需要自然地添加引用标识。既然用户提供了引用,我应该基于这些引用构建回答,并在合适处添加引用,例如[^1]。引用内容:-[^1]:定义多态和应用场景。-[^2]:实现和应用。-[^3]:Java中实现原理。-[^4]:一个实例。用户说这些引用仅供参考,不是真正的需求,但要参考上次问题。既然没有上次,我应该直接回答问题。生成相关问题:在结束时生成相关问题。格式:回答结构清晰,帮助用户逐步解决问题。可能的回答结构:-先介绍概念:什么是多态?-然后讨论实现:在编程中如何实现多态(焦点在Java,因为引用中提到Java)。-再讲应用:应用场景,比如消除耦合、提高可维护性等。-给出一个简单的例子(基于引用[^4])。-最后生成相关问题。关于数学表达式:用户问题涉及编程,没有明显的数学表达式,但如果提到公式,就用LaTeX。比如,在解释时,如果有数学表达。在编程上下文中,多态通常是概念性的,不太需要数学表达式,但如果有不等式、方程等用$...$。例如,没有立即相关的数学。确保使用中文。步骤:1.**概念定义**:描述多态的含义。2.**实现机制**:在Java中的实现(继承、接口、重写等)。3.**应用场景**:列举应用。4.**实例**:基于引用[^4]给出一个简化的代码片段或描述。5.**结束**:总结。6.**生成相关问题**。在回答中,引用引用时,在段落末尾添加引用标识。例如:多态允许不同对象对相同消息响应[^3]。生成相关问题:类似于示例中的“相关问题”。相关问题例子:1.多态在Java中的具体实现方式是什么?2.多态的好处是什么?3.如何处理多态时的编译时类型和运行时类型?4.多态和抽象类的区别?基于用户兴趣。最终回答框架:-概念部分:简述多态是什么。-实现部分:如何在编程中实现(使用Java作为例子)。-应用部分:应用场景。-如果有代码示例,用代码块。-生成2-3个相关问题。</think> ### 多态的概念、实现和应用详解 多态是面向对象编程(OOP)中的一个核心概念,它允许不同类型的对象对同一方法调用做出不同的响应。简而言之,多态通过“一个接口,多种实现”的方式,实现代码的灵活性和可复用性[^1]。例如,你可以使用父类引用操作子类对象,而具体方法执行取决于对象的实际类型。这不仅消除了类型耦合,还简化了代码维护和扩展[^2]。下面我将从概念、实现到应用逐步展开解释。 #### 1. **多态的概念** 在编程中,多态Polymorphism)源于希腊词“poly”(多)和“morph”(形态),意为“多种形态”。它基于面向对象的原则:**继承**和**接口**。多态允许你定义一个通用接口(如父类或接口类型),而具体实现由子类重写。这样,同一方法名(如 `calculateArea()`)可以在不同类(如正方形、圆形)中产生不同的行为。 - **关键特性**: - **动态绑定**:在运行时确定调用哪个方法,而非编译时,这提高了灵活性。 - **向上转型**:子类对象可以赋给父类引用,实现“统一操作”。 例如,在Java中,你可以用 `Shape shape = new Circle();`,当调用 `shape.draw()` 时,实际执行的是 `Circle` 类的 `draw()` 方法,而不是 `Shape` 类的版本[^3]。 #### 2. **多态在编程中的实现** 多态的实现主要依赖于面向对象的继承机制和接口定义。在Java中,有两种常见方式: - **通过继承实现多态**: - 子类重写父类方法,编译时检查父类方法,运行时调用子类方法。 - 原理:基于方法重写(Override)和动态绑定(Dynamic Binding),使用JVM的虚方法表(vtable)来实现。 - 公式描述:动态绑定时,执行的方法取决于对象的实际类型。设父类为 $P$,子类为 $C$,则有: $$ \text{调用 } P.\text{method()} \rightarrow \text{实际执行 } C.\text{method()}, \quad \text{如果 } C \text{ 实现了 } \text{method()}。 $$ - **通过接口实现多态**: - 接口定义方法签名,不同类实现同一接口,保证行为一致性。 - 例如,创建一个 `Shape` 接口,所有形状类(如 `Square`, `Circle`)实现它并重写 `calculateArea()` 方法[^4]。 - **实现要点**: - **步骤示例**(基于引用[^4]): 1. 定义父类或接口:创建抽象类或接口来声明通用方法。 2. 子类重写方法:各个子类提供具体实现。 3. 使用多态引用:在主类中,用父类类型引用实例化对象。 - **代码示范**: ```java // 父类或接口 abstract class Shape { public abstract double calculateArea(); // 抽象方法,子类必须重写 } class Circle extends Shape { private double radius; public Circle(double r) { this.radius = r; } @Override public double calculateArea() { return Math.PI * radius * radius; // 圆的面积计算 } } class Square extends Shape { private double side; public Square(double s) { this.side = s; } @Override public double calculateArea() { return side * side; // 正方形的面积计算 } } // 主类应用多态 public class Main { public static void main(String[] args) { Shape[] shapes = {new Circle(2.0), new Square(3.0)}; for (Shape shape : shapes) { System.out.println("Area: " + shape.calculateArea()); // 运行时自动调用正确的实现 } } } ``` - **好处**:这种方法减少了代码重复,使主类无需关心具体类型[^2]。 #### 3. **多态的应用场景** 多态在编程中广泛应用,因为它通过分离接口(做什么)和实现(怎么做),提升代码的可扩展性、可维护性和复用性。主要应用包括: - **框架设计**:在框架(如Spring或Hibernate)中,多态允许插件式扩展,开发者只需实现接口,框架自动适配(如数据库连接接口的不同实现)[^3]。 - **GUI开发**:在图形界面库(如JavaFX)中,统一事件处理方法(如 `onClick()`),不同控件(按钮、文本域)提供各自的行为[^1]。 - **算法抽象**:在排序或图形处理中,通用算法(如 `sort()`)可处理不同类型对象,子类实现具体逻辑(如快速排序或冒泡排序)。 - **测试和模拟**:使用多态简化单元测试,通过模拟对象(Mock Objects)替换真实实现[^2]。 - **性能提升**:减少条件语句(如 `if-else`),提高代码效率和可读性[^4]。 总之,多态是面向对象编程的基础特性,它使代码更模块化和弹性化。通过利用继承和接口,我们可以编写出更灵活的应用程序[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值