Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4Mobile wallpaper 5Mobile wallpaper 6Mobile wallpaper 7Mobile wallpaper 8
2109 字
11 分钟
Java:多态
2026-03-15

目录#

在代码的编写工程中,会遇到功能类似的函数,比如猫和狗都会叫,只是叫声不同。如果将其抽象出来宠物的概念,就引申出了多态的概念

一、多态#

多态是同一个行为具有多个不同表现形式或形态的能力。 多态性是对象多种表现形式的体现。 比如说宠物这个对象可以有不同的表达方式,可以是猫,可以是狗,当我们跟服务员说:“我要一个宠物。”那么店员可能会给你一个猫也有可能是狗,这样我们就说宠物具有多态性。 例如以下代码:

public class Animal {
public String name;
public int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println(name + "正在吃饭");
}
}
public class Cat extends Animal{
public Cat(String name, int age) {
super(name, age);
}
public void eat() {
System.out.println(name + "正在吃鱼");
}
}
public class Dog extends Animal{
public Dog(String name, int age) {
super(name, age);
}
public void eat() {
System.out.println(name + "正在吃骨头");
}
}
public class Test {
public static void eat(Animal animal) {
animal.eat();
}
public static void main(String[] args) {
Cat cat = new Cat("咪咪", 2);
Dog dog = new Dog("旺财", 3);
eat(cat);
eat(dog);
}
}

运行的结果是

咪咪正在吃鱼
旺财正在吃骨头

这时候我们发现,相同的函数eat(),对于不同的对象catdog,会对应不同的函数。 多态的使用必须满足下列三个条件: 1.必须要在继承体系下 2.子类要对父类的方法进行重写 3.通过父类的引用调用重写的方法 其中第二点对应的是方法的重写,第三点对应的是对象的向下转型,接下来会分成这两个部分进行阐述。

二、方法的重写#

1.重写的概念#

重写(override)是子类对父类非静态、非private、非final、非构造方法的实现过程的改写,要求名称,参数列表相同,改变的是函数的核心(需要注意的是,方法重写不要求返回值相同,但必须是父类返回值的派生类,比如AnimalDog)。 好处是子类可以根据需要,定义特定于自己的行为,也就是说子类可以根据自己的需要实现父类的方法。 例如下面的方法就构成重写:

public class Animal {
public String name;
......
public void eat() {
System.out.println(name + "正在吃饭");
}
}
public class Dog extends Animal{
......
public void eat() {
System.out.println(name + "正在吃骨头");
}
}
public class TestDog{
public static void main(String args[]){
Animal a = new Animal(); // Animal 对象
Animal b = new Dog(); // Dog 对象
a.move();// 执行 Animal 类的方法
b.move();//执行 Dog 类的方法
}
}

结果是:

动物可以移动
狗可以跑和走

可以看到哪怕都是Animal类,a类会调用Animal类的move()方法,但是b类却会调用Dog类的move()方法。 这是由于在编译阶段,只是检查参数的引用类型。 然而在运行时,Java 虚拟机 (JVM) 指定对象的类型并且运行该对象的方法。 因此在上面的例子中,之所以能编译成功,是因为Animal类中存在move方法,然而运行时,运行的是特定对象的方法。

2.重写的原则#

方法重写详细的原则如下图: 图片取自https://www.w3cschool.cn/java/java-override-overload.html

3.super关键词的使用#

当子类需要调用父类的被重写方法的时候,可以用super关键词。

class Animal{
public void move(){
System.out.println("动物可以移动");
}
}
class Dog extends Animal{
public void move(){
super.move(); // 应用super类的方法
System.out.println("狗可以跑和走");
}
}
public class TestDog{
public static void main(String args[]){
Animal b = new Dog(); //
b.move(); //执行 Dog类的方法
}
}

以上实例编译运行结果如下:

动物可以移动
狗可以跑和走

4.重写和重载#

方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载 (Overloading)。 方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写 (Overriding)。

一句话概括就是:重载是类的多态性的体现,重写是子类和父类的多态性的体现。 具体的书写方式也有区别。

区别点重写重载
参数类型不能修改必须修改
返回类型不能修改(除非构成子父类关系)可以修改
访问限制符不能作更严格的限制可以修改
异常可以减少或删除,一定不能抛出新的或者更广的异常可以修改

三、向下转型和向上转型#

1.向上转型#

即创建一个子类对象,并当作是父类对象来使用。 更抽象点,就是把“更具体的类型”当成“更一般的类型”来用。 举个例来讲,你有一只狗,那我把他当作是一只宠物来使用与宠物相关的规定也是完全可行的。

一个简单的例子(直接赋值)#

public interface Vegetarian{}
public class Animal{}
public class Deer extends Animal implements Vegetarian{}
Deer d = new Deer();
Animal a = d;
Vegetarian v = d;
Object o = d;

Deer 既是 Animal,也是 Vegetarian,同时任何类最终也都是 Object

多态性的实例解析如下: 一个 Deer IS-A(是一个) Animal 一个 Deer IS-A(是一个) Vegetarian 一个 Deer IS-A(是一个) Deer 一个 Deer IS-A(是一个)Object

向上转型的过程实际是一种“视角”的转变。 我们知道,访问一个对象的唯一方法就是通过引用型变量。 因此当我们声明Animal a = d;的时候,实际上a指代的同样是d的鹿,只是我们用一个更加一般和抽象的视角看待它。 这样我们就可以用Animal类的方法来处理对象了。

方法传参#

除了直接复制,向上转型还可以以方法传参的形式进行,比如前面的:

public class Test {
public static void eat(Animal animal) {
animal.eat();
}
public static void main(String[] args) {
...
eat(cat);
eat(dog);
}
}

因为猫猫狗狗都是动物,因此可以统一送进Animal的入口,调用方法。 这样就可以把猫猫狗狗都作为参数,调用eat()函数,实现代码的复用。

返回值#

向上转型还可以应用在方法的返回值中,如下:

public class TestAnimal {
//作返回值:返回任意子类对象
public static Animal buyAnimal(String var){
if("狗".equals(var) ){
return new Dog("狗狗",1);
}else if("猫" .equals(var)){
return new Cat("猫猫", 1);
}else{
return null;
}
}
public static void main(String[] args) {
Animal animal = buyAnimal("狗");
animal.eat();
animal = buyAnimal("猫");
animal.eat();
}
}

前面是作为参数,也就是设立了一个宽松的入口,而返回值则是设立了一个宽松的出口,猫猫狗狗可以带着自己的属性走出来。 但是这样出来的对象还是Animal,我们没办法调用子类的特殊方法,那么有没有办法可以解决呢?那就是向下转型

2.向下转型#

向下转型的形式是类型强转,比如:

public class TestAnimal {
public static void main(String[] args) {
Dog dog = new Dog("小七", 1);
// 编译失败,编译时编译器将animal当成Animal对象处理
// 而Animal类中没有bark方法,因此编译失败
Animal animal = dog;
animal.bark();
// 类型强转成Dog类对象,因为animal本来就指代的是狗,因此强转并没有风险
dog = (Dog)animal;
dog.bark();
}
}

但是我们要注意,当我们看待animal的时候,我们是不知道它具体是哪只动物的,因此向下转型其实是在向编译器打包票,拍拍胸脯说放心好了这是一只狗,所以编译器才允许调用bark()方法。 但是如果把animal强行转换成了一只猫,编译器也不会允许调用猫的方法的,所以说类型强转是有一定风险的。 下一章讲接口!!

Java:多态
https://blog.csdn.net/2501_93882415/article/details/158969681?spm=1001.2014.3001.5502
作者
Mem0rin
发布于
2026-03-15
许可协议
MIT

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00