Episode-8 Java运行时多态的简单使用
当谈论Java中的面向对象编程时,一个重要的概念就是多态性(Polymorphism)。Java多态性是指对象可以有多种形态。在Java中,多态性有两种形式,一种是编译时多态性,另一种是运行时多态性。Java中的编译时多态主要体现在方法的重载(overload)上,相信大家已经对此十分了解,故在此文章中不再赘述。
让我们一起探究Java的运行时多态吧!
(下面的多态均为运行时多态)
本期学习相关的知识
- 使用抽象类的多态
- 使用接口的多态
- 使用泛型的多态
使用抽象类的多态
多态有两个条件,一是继承,二是重写(override)。
假设我们需要处理多种动物,每种动物都需要吃东西,但是每种动物吃饭的具体特性都不相同,为了简化处理过程,我们需要使用多态。
让我们先定义一个抽象的父类"Animal":
public abstract class Animal {
public abstract void eat();
}
再写几个子类来继承并重写eat()
方法:
子类:“猫”:
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("Cat is eating fish");
}
}
子类:“狗”:
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("Dog is eating meat");
}
}
现在,我们可以再写一个程序来测试上面的代码:
public class Main {
public static void main(String[] args) {
Animal animal1 = new Cat();
Animal animal2 = new Dog();
animal1.eat(); // 输出 "Cat is eating fish"
animal2.eat(); // 输出 "Dog is eating meat"
}
}
下面是在上述示例在命令行中运行的结果:
虽然每种动物的eat()
方法都不尽相同,但在Main.java中,我们对它们使用了相同的Animal调用,却正确地输出了具体动物的特定eat()
方法里的内容。
使用接口的多态
接口是一个重要的概念,在这篇文章中我们暂且讨论它在简单的多态中的使用。
假如我们需要对不同的形状进行处理,那么我们根据之前的经验,应该先定义一个接口,各种具体的形状应该各自实现这个接口。
下面是接口"Shape"的一个示例:
public interface Shape {
public void draw();
}
接下来,我们定义两个形状————圆形"Circle"和方形"Square"。
Circle.java的内容:
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a circle");
}
}
Square.java的内容:
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Drawing a square");
}
}
同样的,让我们写一个测试程序Main.java:
public class Main {
public static void main(String[] args) {
Shape shape1 = new Circle();
Shape shape2 = new Square();
shape1.draw(); // 输出 "Drawing a circle"
shape2.draw(); // 输出 "Drawing a square"
}
}
上述程序在命令行中的运行结果如下:
上面只是一个简单的示例,以后我们会分析更加复杂的程序。
使用泛型的多态
泛型的用法比较多,具体可以参见:泛型-菜鸟教程
实际上,泛型也是Java多态性的体现。
以"T"为例,在泛型实际引用的类型不同时,会根据具体的类型进行对应的处理。
现在我们可以定义一个泛型类"Box"来切身体会这一点:
public class Box<T> {
private T content;
public void add(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
上面的代码定义了一个泛型类,它被定义为Box<T>
,其中T是一个泛型类型参数,可以被任何Java类或接口代替。这个类表示一个简单的容器,可以存储一个类型为T的对象。
这个类有两个方法:add()
和getContent()
。add()
方法接受一个类型为T的对象作为参数,并将它存储在Box类的私有成员变量content中。getContent()
方法返回存储在content中的对象,这个对象的类型也是T。
使用泛型类的好处是可以在编译时进行类型检查,从而避免在运行时出现类型错误。这个类可以用来存储各种不同类型的对象,只需要在创建实例时指定相应的类型即可。例如:
public class Main {
public static void main(String[] args) {
Box<Integer> intBox = new Box<Integer>();
intBox.add(123);
Box<String> strBox = new Box<String>();
strBox.add("Hello, world!");
System.out.println(intBox.getContent()); // 输出 123
System.out.println(strBox.getContent()); // 输出 "Hello, world!"
}
}
按照惯例,让我们看看它在命令行中的运行结果:
虽然使用泛型的多态与前面两个示例有些微的不同,但它们的核心是:对各种不同的对象进行统一地处理,输出不同的结果。
希望本篇文章会对你的学习有所帮助。