【化神系列】Java多态

简介: 详解JavaSE多态

一、方法的重写

重写(override):也称为覆盖。重写是子类对父类 非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
 class Animal{
    public int size;
    public String color;

     public Animal(int size, String color) {
         this.size = size;
         this.color = color;
     }
     public void move(){
         System.out.println("此动物正在移动");
     }
 }
 class Dog extends Animal{
    public String name;
    public int age;

     public Dog(int size, String color, String name, int age) {
         super(size, color);
         this.name = name;
         this.age = age;
     }
     //子类对父类方法进行重写
     @Override
     public void move() {
         System.out.println("正在快速移动");
     }
 }

方法重写的规则

  • 子类在重写父类方法时,一般必须与父类方法原型一致:返回值类型 方法名(参数列表)要完全一致,使用@Override注解来进行合法性检验
  • 被重写的方法的返回值一般要相同
  • 重写之后的方法,访问权限不能比父类中被重写的方法的访问权限更低

    ✅方法重写与重载的区别?

    区别点 重写(override) 重载(override)
    参数列表 一定不能修改 必须修改
    返回类型 一定不能修改【除非可以构成父子类关系】 可以修改
    访问限定符 一定不能做更严格的限制(可以降低限制) 可以修改
    方法名称 必须相同 必须相同
方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现

image-20220902182616462

二、向上转型和向下转型

  • 向上转型
class Fruit{
    public void show() {
        System.out.println("this is a fruit");
    }
}
class Apple extends Fruit{
    @Override
    public void show() {
        System.out.println("this is a apple");
    }
    public void test() {
        System.out.println("i am a apple");
    }
}
 public class TestDemo {
     public static void main(String[] args) {
         //向上转型
         //实例化Apple类,并新建一个Fruit类的引用变量引用该实例,调用实例的show()方法
         Fruit fruit = new Apple();
         fruit.show();
     }
 }

image-20220902215414906

调用实例的test()方法

fruit.test();

image-20220902215625608

分析:

向上转型即使用父类的引用变量去引用子类的实例, 当向上转型之后,父类引用变量可以访问子类中属于父类的属性和方法,但是不能访问子类独有的属性和方法

例子中由于子类重写了父类的show()方法,所以调用的show()方法是子类的show()方法,输出结果为:“this is a apple”,而调用子类的test()方法则会报错

下面代码中一个引用调用一个方法,因为这个引用所引用的对象不一样,导致调用的这个方法,所表现的行为不一样,这种思想就叫做多态

class Fruit{
    public void show() {
        System.out.println("this is a fruit");
    }
}
class Orange extends Fruit{
    @Override
    public void show(){
        System.out.println("this is a C");
    }
}

class Apple extends Fruit{
    @Override
    public void show() {
        System.out.println("this is a apple");
    }
    public void test() {
        System.out.println("i am a apple");
    }
}
 public class TestDemo {
     public static void main(String[] args) {
         Apple apple = new Apple();
         Orange orange = new Orange();
         func(apple);
         func(orange);
     }
     //方法传参
     public static void func(Fruit fruit){
         fruit.show();
     }
     //方法返回
     public static Fruit func2(){
         return new Apple();
     }
 }
  • 向下转型
 public class TestDemo {
     public static void main(String[] args) {
          Fruit fruit = new Apple();
          Apple apple = (Apple)fruit;
          fruit.show();
     }
}

上述代码是允许的,因为fruit引用的对象原本就是Apple对象向上转型得到的,在对fruit向下转型后得到的还是Apple类的对象,能够被Apple类的引用变量引用。

实例化Apple类,并新建一个Fruit类的引用变量“fruit”引用该实例,然后新建一个Orange类的引用变量,引用向下转型的“fruit”变量,代码如下:

Fruit fruit = new Apple();
Orange orange = (Orange) fruit;

上述代码虽然能够编译成功,但是在运行的时候会报错,因为fruit对象是由Apple对象向上转型得到的,只能够向下转型成Apple对象,不能够向下转型成Orange对象。

image-20220903103523891

向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为true,则可以安全转换

 public class TestDemo {
     public static void main(String[] args) {
         Fruit fruit = new Apple();
         if(fruit instanceof Apple){
              Apple apple = (Apple)fruit;
          }
          fruit.show();
}

三、多态的优缺点

  • 提高了代码的可维护性,主要体现在每一个派生类编写功能调用,只需要对抽象基类进行处理即可。
  • 提高了代码的可扩展性,主要体现在派生类的功能可以被基类的方法或引用变量所调用。

避免在构造方法中调用重写的方法

class B {
    public B() {
        func();
    }
    public void func() {
        System.out.println("B.func()");
    }
}
class D extends B {
    private int num = 1;
    @Override
    public void func() {
        System.out.println("D.func() " + num);
    }
}
public class TestDemo2{
    public static void main(String[] args) {
        D d = new D();
    }
}

image-20220903163928824

【说明】

  • 构造D对象的同时,会调用B的构造方法;
  • B的构造方法中调用了 func方法,此时会触发 动态绑定,会调用到D中的 func,并且由于没有初始化num,所以num = 0.
相关文章
|
29天前
|
算法 Java 程序员
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
53 9
|
29天前
|
Java 开发者
在Java面向对象编程的广阔海洋中,多态犹如一股深邃的潜流,它推动着代码从单一走向多元,从僵化迈向灵活。
在Java面向对象编程的广阔海洋中,多态犹如一股深邃的潜流,它推动着代码从单一走向多元,从僵化迈向灵活。
33 7
|
29天前
|
Java 开发者
那些年,我们一同踏入Java编程的大门,多态,这个充满魔法的名字,曾无数次点亮我们探索面向对象编程的热情。
那些年,我们一同踏入Java编程的大门,多态,这个充满魔法的名字,曾无数次点亮我们探索面向对象编程的热情。
40 5
|
29天前
|
Java 程序员
让我们一起探讨Java多态的奥秘,看看它是如何打破“一刀切”的局限,让我们的代码更加生动多彩
让我们一起探讨Java多态的奥秘,看看它是如何打破“一刀切”的局限,让我们的代码更加生动多彩
33 5
|
30天前
|
Java 程序员
Java中的继承和多态:理解面向对象编程的核心概念
【8月更文挑战第22天】在Java的世界中,继承和多态不仅仅是编程技巧,它们是构建可维护、可扩展软件架构的基石。通过本文,我们将深入探讨这两个概念,并揭示它们如何共同作用于面向对象编程(OOP)的实践之中。你将了解继承如何简化代码重用,以及多态如何为程序提供灵活性和扩展性。让我们启程,探索Java语言中这些强大特性的秘密。
|
7天前
|
Java 编译器
Java——类与对象(继承和多态)
本文介绍了面向对象编程中的继承概念,包括如何避免重复代码、构造方法的调用规则、成员变量的访问以及权限修饰符的使用。文中详细解释了继承与组合的区别,并探讨了多态的概念,包括向上转型、向下转型和方法的重写。此外,还讨论了静态绑定和动态绑定的区别,以及多态带来的优势和弊端。
20 9
Java——类与对象(继承和多态)
|
1月前
|
Java 开发者
【Java基础面试十五】、 说一说你对多态的理解
这篇文章解释了多态性的概念:在Java中,子类对象可以赋给父类引用变量,运行时表现出子类的行为特征,从而允许同一个类型的变量在调用同一方法时展现出不同的行为,增强了程序的可扩展性和代码的简洁性。
【Java基础面试十五】、 说一说你对多态的理解
|
23天前
|
安全 Java 编译器
Java多态
Java多态
13 2
|
29天前
|
搜索推荐 Java
揭秘Java多态背后的奥秘,探索对象们是如何做到“千人千面”的
揭秘Java多态背后的奥秘,探索对象们是如何做到“千人千面”的
34 3
|
29天前
|
Java
在Java编程的江湖中,有一本传说中的“武林秘籍”,它不是刀光剑影的武学心法,而是能够让代码变得灵动、高效的秘密武器——多态。
在Java编程的江湖中,有一本传说中的“武林秘籍”,它不是刀光剑影的武学心法,而是能够让代码变得灵动、高效的秘密武器——多态。
28 1