JavaSE面向对象(八)-多态
  eZw8kcl3fQWu 2023年11月19日 16 0



文章目录

  • 1.多态定义及存在条件
  • 1.1.多态的定义
  • 1.2.多态的存在条件
  • 1.3.多态的格式
  • 1.4.多态中的成员特点
  • 2. 多态的特点
  • 3. 引用类型转换
  • 3.1 为什么需要引用类型转换
  • 3.2 向上转型(自动转换)
  • 3.3 向下转型(父亲变儿子,需要强制转换)
  • 2.4 向下转型的问题
  • 2.5 instanceof关键字详解


1.多态定义及存在条件

1.1.多态的定义

多态是什么?

  • 多态是同一个行为具有不同的表现形式或形态的能力
  • 同一方法可以根据触发对象的不同而采用不同的行为方式

一个人在同一时间可以有不同的特征。是一个男人,同时也是一个父亲,一个丈夫,一个员工。所以同一个人在不同的情况下有不同的行为。这被称为多态性。

多态性被认为是面向对象编程的重要特性之一。多态性允许我们以不同的方式执行单个操作。换句话说,多态性允许您定义一个接口并有多个实现,意思是多种形式;

多态就是事物的多种形态,一个对象在不同条件下所表现的不同形式

1.2.多态的存在条件

  1. 继承或实现:在多态中必须存在有继承或实现关系的子类和父类
  2. 方法的重写:子类对父类中的某些方法进行重新定义(重写,使用@Override注解进行重写)
  3. 基类引用指向派生类对象,即父类引用指向子类对象,父类类型:指子类对象继承的父类类型,或实现的父接口类型

1.3.多态的格式

  • 父类类型 对象名 = new 子类类型();
  • 然后通过 对象名.方法名()调用在子类中重写的方法

多态体现为父类引用变量可以指向子类对象:定义了一个父类类型的引用,指向新建的子类类型的对象,由于子类是继承他的父类的,所以父类类型的引用是可以指向子类类型的对象的

1.4.多态中的成员特点

  • 多态成员变量:编译运行看左边

父类Animal:

//父类
public class Animal {
 
    public int age = 11;
    
}

子类Dog:

//子类
public class Dog extends Animal {
 
    public int age = 33;
    
}

测试类:

public class DemoApplication {
 
    public static void main(String[] args) {
 
        //父类类型 对象 = new 子类类型()
        Animal dog = new Dog();
        System.out.println(dog.age);
    }
}

控制台打印输出:父类中定义的age

此处举例Animal是父类,Dog是子类

Animal dog = new Dog();     //Animal是引用类型,Dog是实际类型
System.out.println(dog.age) //dog的引用类型是Animal,所以取到的是父类Animal中的值,说白了dog是属于Animal类,Animal中变量的值是多少就通过对象就取得多少
  • 多态成员方法:编译看左边,运行看右边

父类Animal:

//父类
public class Animal {
 
    public void eat() {
        System.out.println("午餐吃狗粮");
    }
 
}

子类Dog:

//子类
public class Dog extends Animal {
    
    @Override
    public void eat() {
        System.out.println("晚餐吃狗粮");
    }
}

启动类:

public class DemoApplication {
 
    public static void main(String[] args) {
 
        //父类类型 对象 = new 子类类型()
        Animal dog = new Dog();
 
        dog.eat();
    }
}

控制台打印输出:调用的是子类中重写的方法

晚餐吃狗粮

2. 多态的特点

  1. 多态情况下,子类和父类存在同名的成员变量时,访问的时父类的成员变量
  2. 多态情况下,子父类存在同名的非静态成员方法时,访问的是子类中重写的方法
  3. 多态情况下,不能访问子类独由的方法

父类Animal保持不变:

//父类
public class Animal {
    
    public void eat() {
        System.out.println("午餐吃狗粮");
    }
 
}

子类Dog:增加子类读有的方法walk()

//子类
public class Dog extends Animal {
 
    
    public void walk(){
        System.out.println("子类独有的方法");
    }
    
    
    @Override
    public void eat() {
        System.out.println("晚餐吃狗粮");
    }
}

启动项:walk()方法爆红,即编译报错,

public class DemoApplication {
 
    public static void main(String[] args) {
 
        //父类类型 对象 = new 子类类型()
        Animal dog = new Dog();
 
        dog.eat();  //访问的是子类中重写的方法
 
        dog.walk();  //walk方法爆红,即编译报错,编译看左边,dog类的实例对象Animal没有walk()这个方法,所以编译报错
 

    }
}
根据多态成员方法中编译看左边,运行看右边的原理
Animal  dog  =  new Dog();
可知 左边的Animal引用类型中没有walk()这个方法,故编译不通过,编译爆红

3. 引用类型转换

3.1 为什么需要引用类型转换

  • 上面的例子说明了,在多态情况下,使用Animal引用类型构建出来的对象dog无法访问子类Dog所独有的方法walk();强行调用时方法会爆红,编译出错,即我们所说的编译看左边,运行看右边
  • 而且我们在多态情况下调用方法时,首先会检查等式左边的引用类型(父类)中是否有该方法存在,如果父类中没有该方法,则编译器直接报错,也就代表着,父类无法调用子类独有的方法
  • 既然编译都出错了,更别说运行了,这也是多态所造成的,因此如果我们想要调用子类的方法,必须做到向下转型

3.2 向上转型(自动转换)

先了解什么向上转型(儿子变父亲)

JavaSE面向对象(八)-多态_Java编程


多态本身是子类向父类向上转换(自动转换)的过程,这个过程是默许的,当父类引用指向一个子类对象时,就是向上转型

父类引用指向子类对象:
Animal dog = new Dog()

左边的Animal是引用类型,而dog是由右边的Dog实例对象new出来的,在上面这个等式中,左边的引用Animal指向了子类的对象dog,原本是子类对象的dog完成了向上转型.

对于父类和子类的关系,直接用图来描述

JavaSE面向对象(八)-多态_java_02


Animal父类是大范围的类型,而Cat和Dog类均属于动物类的子类,所以对于子类这种范围小的,我们可以自动转型给父类的变量,儿子向上转型,父亲是唯一的,因此是自动转换

使用格式:

父类类型 变量名 = new 子类类型();
Animal dog = new Dog()
通过由实例变量Dog类new出来的变量dog作为中介,使得引用变量Animal有所指向,从而完成了向上转型
相当于是
Animal dog = (Animal) new Dog()

3.3 向下转型(父亲变儿子,需要强制转换)

向上转型是一个子类变成父类的过程,下面介绍向下转型

向下转型:

JavaSE面向对象(八)-多态_java_03

向下转型是父类向子类转换的过程,这个过程需要强制转换(父亲变儿子肯定是需要条件的),一个可以将父类对象转换为子类对象,可以使用强制类型转换的格式,这便是向下转型

JavaSE面向对象(八)-多态_java_04


对于Dog、Cat这些子类来说,他们只是父类Animal的一部分,而对于父类来说。他拥有更多的子类 牛、羊等,所以一旦父类要转换成子类,就必须指定要变成哪个子类,必须有指向性,所以向下转型才是强制转换

使用格式:

向上转型
父类类型 变量名 = new 子类类型();
Animal dog = new Dog()
向下转型
子类类型 子类变量名 = (子类类型) 父类变量名
Dog dog1 = (Dog) dog;
dog1.walk; //此时可以使用子类独有的方法了

代码示例如下:

父类Animal:

//父类
public class Animal {
 
    public void eat() {
        System.out.println("午餐吃狗粮");
    }
 
}

子类Dog:包含有子类独有的方法walk()

//子类
public class Dog extends Animal {
 
 
    public void walk(){
        System.out.println("子类独有的方法");
    }
 
 
    @Override
    public void eat() {
        System.out.println("晚餐吃狗粮");
    }
}

测试类

public class DemoApplication {
 
    public static void main(String[] args) {
 
        //父类类型 对象 = new 子类类型()
        Animal dog = new Dog();
        //向下转型
        //子类类型 子类变量名 = (子类类型) 父类变量名
        Dog dog1 = (Dog) dog;
 
        dog.eat();  //访问的是子类中重写的方法
 
        //通过向下转型的子类对象调用子类独有的方法
        dog1.walk();  //walk方法爆红,即编译报错,编译看左边,dog类的实例对象Animal没有walk()这个方法,所以编译报错
 
 
    }
}

通过
Dog dog1 = (Dog) dog;完成向下转型
再利用向下转型成功的子类对象dog1调用子类中独有的方法walk()

控制台打印输出:

晚餐吃狗粮
子类独有的方法

所以对于多态中,无法使用子类特有的方法也通过向下转型,将父类类型强制转换为某个子类类型后,再进行方法的调用

2.4 向下转型的问题

虽然可以通过向下转型可以调用子类独有的方法,但也会产生下面的问题

增加一个子类Cat类,

Cat类中有其独有的方法sleep()

//Cat类通过extends关键字继承父类Animal
public class Cat extends Animal {
 
 
 
    public void sleep(){
        System.out.println("Cat类独有的方法");
    }
 
    @Override
    public void eat() {
        System.out.println("晚餐吃猫粮");
    }
}

父类Animal:

//父类
public class Animal {
 
    public void eat() {
        System.out.println("午餐吃狗粮");
    }
 
}

子类Dog类:

//子类
public class Dog extends Animal {
 
 
    public void walk(){
        System.out.println("Dog类独有的方法");
    }
 
 
    @Override
    public void eat() {
        System.out.println("晚餐吃狗粮");
    }
}

测试类:

public class DemoApplication {
 
    public static void main(String[] args) {
 
        //向上转型
        //父类类型 对象 = new 子类类型()
        Animal cat = new Cat();
        //向下转型
        //子类类型 子类变量名 = (子类类型) 父类变量名
        Dog dog1 = (Dog) cat;
 
 
        //通过向下转型的子类对象调用子类独有的方法
        dog1.walk();  //walk方法爆红,即编译报错,编译看左边,dog类的实例对象Animal没有walk()这个方法,所以编译报错
 
    }
}

控制台打印输出:爆出异常ClassCastException,即类型转换异常

JavaSE面向对象(八)-多态_Java知识点_05


分析:为什么会爆出类型转换异常

  • 因为 在启动项中,向上转型的过程,Animal cat = new Cat(); cat对象是由子类Cat构造出来的
  • 而向下转型的过程中 Dog dog1 = (Dog) cat; 却将其变成了Dog 类的对象,
  • Dog类和Cat类都是Animal类的儿子类 ,

上面的步骤中的第二步将子类Cat的对象cat变成了兄弟类的对象dog,这就不是向下转型了,因此会报类型转换异常

那么如何避免这种异常呢 ,就需要使用instanceof关键字?

2.5 instanceof关键字详解

Java为我们提供了一个关键字instanceof,它可以帮助我们避免出现ClassCastException这样的异常,

格式:

变量名 instanceof 数据类型

解释:

如果变量属于该数据类型或者其子类型,返回true
如果变量不属于该数据类或者其子类型,返回false

直接拿启动项来进行说明,

public class DemoApplication {
 
    public static void main(String[] args) {
 
        //向上转型
        //父类类型 对象 = new 子类类型()
        Animal animal = new Cat();
 
 
        //向下转型
        //子类类型 子类变量名 = (子类类型) 父类变量名
        if ( animal instanceof Cat){
            Cat cat = (Cat) animal;
            cat.sleep();
        }else if(animal instanceof Dog){
            Dog dog = (Dog) animal;
            dog.walk();
        }
 
    }
}

在进行了向上转型之后,在向下转型的过程中利用if语句来进行判断,而判断条件正是向上转型产生的变量与子类之间的关系

控制台打印输出:

Cat类独有的方法


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月19日 0

暂无评论

推荐阅读
eZw8kcl3fQWu