Java中的多态性与动态绑定详解
立即解锁
发布时间: 2025-08-18 01:52:46 阅读量: 1 订阅数: 9 

### Java 中的多态性与动态绑定详解
#### 1. 多态性概述
在面向对象编程(OOP)中,多态性是三个最重要的特性之一,另外两个是封装和继承。多态性(Polymorphism)一词源于希腊语,意为“具有多种形式”。在不同领域中,多态性有不同的含义:
- 在化学和矿物学中,多态性指的是一种物质可以以两种或更多种不同的晶体形式存在。
- 在动物学中,多态性指的是一个物种具有两种或更多种不同的形态,例如由同一只蜂王产生的不同蜂种在蜂巢中执行不同的功能。
- 在计算机科学中,多态性指的是不同类型的对象对同一个方法调用做出不同的响应。
在 Java 中,我们可以声明一个通用类型的引用变量来引用不同类型的对象。最通用的引用变量类型是 `Object` 类型。例如:
```java
Object obj;
```
一旦声明了 `Object` 类型的引用变量,就可以用它来引用任何类型的对象。下面是一个简单的示例,定义了 `Dog` 和 `Cat` 两个类,每个类都重写了 `Object` 类的 `toString` 方法:
```java
// Dog.java
public class Dog {
public String toString() {
return "Woof! Woof!";
}
}
// Cat.java
public class Cat {
public String toString() {
return "Meow! Meow!";
}
}
// Pets.java
import java.util.Scanner;
public class Pets {
public static void main(String[] args) {
Scanner stdIn = new Scanner(System.in);
Object obj;
System.out.print("Which type of pet do you prefer?\n" +
"Enter d for dogs or c for cats: ");
if (stdIn.next().equals("d")) {
obj = new Dog();
} else {
obj = new Cat();
}
System.out.println(obj.toString());
System.out.println(obj);
}
}
```
在这个示例中,`obj` 引用变量可以引用 `Dog` 对象或 `Cat` 对象,具体调用哪个 `toString` 方法取决于 `obj` 引用的对象类型。程序中打印 “Woof! Woof!” 两次的原因是:第一个 `println` 语句显式调用了 `toString` 方法,第二个 `println` 语句隐式调用了 `toString` 方法,当引用变量单独出现在字符串上下文中时,编译器会自动在引用变量后面追加 `.toString()`。
#### 2. 动态绑定
多态性和动态绑定密切相关,但它们并不相同。多态性是一种行为形式,而动态绑定是实现这种行为的机制。具体来说,多态性是指不同类型的对象对同一个方法调用做出不同的响应,而动态绑定是指 JVM 为了将多态方法调用与特定方法进行匹配所做的操作。
在 JVM 执行方法调用之前,它会确定方法调用的实际调用对象的类型。如果实际调用对象来自类 X,JVM 会将类 X 的方法绑定到该方法调用上;如果实际调用对象来自类 Y,JVM 会将类 Y 的方法绑定到该方法调用上。绑定完成后,JVM 会执行绑定的方法。例如,在 `Pets` 类中的 `System.out.println(obj.toString());` 语句中,根据 `obj` 引用的对象类型,JVM 会将 `Dog` 类或 `Cat` 类的 `toString` 方法绑定到 `obj.toString` 方法调用上,然后执行绑定的方法并打印相应的结果。
动态绑定被称为“动态”是因为 JVM 在程序运行时执行绑定操作,绑定发生在方法执行之前的最后一刻,因此也常被称为“晚期绑定”。与之相对的是静态绑定,一些编程语言在编译时进行方法调用的绑定。Java 的设计者选择动态绑定是因为它有助于实现多态性。
#### 3. 编译细节
在 `Pets` 程序中,我们通过调用 `Dog` 和 `Cat` 类的 `toString` 方法展示了多态行为。那么,如果尝试使用 `Dog` 和 `Cat` 类的 `display` 方法,代码是否能正常工作呢?例如:
```java
Object obj = new Dog();
obj.display();
```
从动态绑定的角度来看,代码似乎可以正常工作,JVM 会看到 `obj` 引用变量中的 `Dog` 对象,并将 `Dog` 类的 `display` 方法绑定到 `obj.display` 方法调用上。但实际上,这段代码无法成功编译,因为编译器会检测到可能存在的问题。
当编译器看到方法调用 `<reference-variable>.<method-name>()` 时,它会检查引用变量的类是否包含被调用方法的定义。在上述示例中,编译器会检查 `obj` 的类 `Object` 是否包含 `display` 方法,由于 `Object` 类不包含 `display` 方法,所以代码会产生编译时错误。而对于 `obj.toString` 方法调用,由于 `Object` 类包含 `toString` 方法,所以代码可以成功编译。
这是否意味着多态性只适用于 `Object` 类中定义的方法呢?幸运的是,并非如此,后续会介绍如何让多态性适用于任何方法。
#### 4. `instanceof` 运算符
每当一个通用引用调用多态方法时,JVM 会根据引用对象的类型来决定调用哪个方法。在代码中,我们也可以显式地做类似的事情。`instanceof` 运算符可以用来检查一个引用对象是否是某个特定类的实例。以下是一个使用 `instanceof` 运算符的示例:
```java
// Pets2.java
import java.util.Scanner;
public class Pets2 {
public static void main(String[] args) {
Scanner stdIn = new Scanner(System.in);
Object obj;
System.out.print("Which type of pet do you prefer?\n" +
"Enter d for dogs or c for cats: ");
if (stdIn.next().equals("d")) {
obj = new Dog();
} else {
obj = new Cat();
}
if (obj instanceof Dog) {
System.out.println("Wag tail");
}
}
}
```
在这个示例中,如果 `obj` 引用的对象是 `Dog` 类或其派生类的实例,程序会打印 “Wag tail”。`instanceof` 运算符为我们提供了一种简单直接的方式来区分通用引用变量可能引用的不同对象类型。
#### 5. 类层次结构中的类之间的赋值
在多态程序中,经常会遇到将一个对象赋值给一个引用,而对象的类和引用的类不同的情况。例如:
```java
class Person {}
class Student extends Person {}
Person p = new Student();
Student s = new Person();
```
第一行代码将 `Student` 对象(实际上是 `Student` 对象的引用)赋值给 `Person` 类型的引用变量,这是合法的赋值,因为 `Student` 是 `Person`
0
0
复制全文
相关推荐










