IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 彻底搞懂Java多态 -> 正文阅读

[Java知识库]彻底搞懂Java多态

目录

引例 - -认识多态??

向上转型

? ??向上转型发生场景

? ??方法覆写(override)

? ??方法覆写的三个要求:

向下转型

向下转型的风险!

instanceof关键字


引例

面向对象编程有三大特征:封装、继承、多态。现在我们对多态展开详细的了解。

  • ?在现实中,如老师,一位具体的老师他既是老师,也是,既表现出了多种形态
  • ?在Java语言中,多态就是一个引用可以表现出多种状态例如:

我们定义两个类:

public class Animal {
    String name;
    public Animal(){}
    public Animal(String name){
        this.name=name;
    }
    public void eat(String food) {
        System.out.println(name+"正在吃"+food);
    }
}
public class Dog extends Animal{
    String name;
    public Dog(String name){
       super(name);//调用父类的有参构造
    }
    public void eat(String food) {
        System.out.println(name+"正在吃"+food);
    }

public static void main(String[] args) {
       Animal animal = new Animal("动物");
        Dog dog = new Dog("小狗");
        animal.eat("食物");
        dog.eat("骨头");
    }

运行结果:

可以看到两个对象调用的都是eat方法,运行结果却不一样,这就是多态的表现。


向上转型

  • 语法:父类 ?引用名称 ?= ?new ?子类实例();那么向上转型怎么使用呢,承接上面的例子。我们做如下转换,将dog引用前面的类换成父类Animal,运行结果和上面一样

Dog继承Animal之间是一种天然的?is a 关系 :dog ia an animal, 所以可以自然而然的向上转型。

有了向上转型之后,我们将代码做如下转变:

public class Test {
    public static void fun(Animal animal,String food){
        animal.eat(food);
    }
    public static void main(String[] args) {
        Animal animal = new Animal("动物");
        Animal dog = new Dog("小狗");
         fun(animal,"食物");
        fun(dog,"骨头");
    }


}

运行结果:?

?

上述代码也中的Animal dog = new Dog("小狗");也可以写成Dog?dog = new Dog("小狗");?

变成Dog类对象后,依然可以使用fun方法,那么,fun方法里是Animal对象,为什么Dog对象可以使用呢?这就是向上转型的原因。只要对象是Animal和它的子类,都可以传入fun方法。

也就是说,不论Animal有多少个子类,fun方法只需要写一次,将参数定义为Animal就可以接受所有它的子类对象。

  • 另个我们知道Dog类和Animal类都有完全相同的eat方法,当主方法如下写时:
Animal animal = new Animal("动物");
Animal dog = new Dog("小狗");
animal.eat("食物");
dog.eat("骨头");

dog向上转型成了Animal类的引用,那么它调用的是哪个类的对象呢??

其实,当发生向上转型时,若调用的方法子类和父类中都有,我们要看是通过哪个类new的对象,该对象就调用该类的方法。

向上转型发生场景

  1. 产生对象时:Animal dog = new Dog();
  2. 方法参数传递:既上面的例子,产生的是Dog类的对象,但用fun方法接收。在传递Dog对象时发生了向上转型。
  3. 方法返回值:如下代码,我们new的是Dog类的实例,test方法返回的却是Animal对象,这就是在返回的时候发生了向上转型。
     public static Animal test(){
            return new Dog("狗狗");
        }
        public static void main(String[] args) {
            Animal a = test();

    综上我们可得:向上转型是为了使参数统一化,父类引用可以接收子类所有对象,同时向上转型是一个非常实用也很重要的概念,读者一定要理解掌握。

方法覆写(override)

定义:发生在有继承关系的类之间,子类定义了和父类完全相同的方法。这种方法就称为方法覆写。

回到我们最开始的例子中:

public static void main(String[] args) {
? ? ? ?Animal animal = new Animal("动物");
? ? ? ? Dog dog = new Dog("小狗");
? ? ? ? animal.eat("食物");
? ? ? ? dog.eat("骨头");
? ? }

eat()就称为方法覆写。

在IDEA中,子类中方法覆写的旁边有一个这样的标,表示发生了方法覆写,在父类中是一个向下的标。点击一下就可以找到父类/子类的这个方法。

?

方法覆写的三个要求:

? ? ? ? 1.只能重写成员方法,不能重写静态方法

//在父类写一个test方法
public static void test(){
    System.out.println("Animal's test");
}

//在子类写一个test方法

public static void test(){
    System.out.println("Dog's test");
}

//在主方法中测试

Animal animal = new Animal("动物");
 Animal dog = new Dog("小狗");     
        animal.test();
        dog.test();

输出结果为:?

可见没有调用Dog类中的test方法,而且在IDEA中没有出现方法覆写的图标,所有这不是方法覆写。

?

? ? ?2.子类中方法的权限修饰符权限要大于或等于父类的??(权限修饰符:private < default < protected < public)

? ? ? ? 另外,方法覆写时不能出现private权限。当方法是包访问权限(default)时,若父类和子类不在同一个包中,就无法方法覆写。

? ? ?3.方法覆写的返回值是基本类型时必须相同,否则至少是向上转型的返回值

若父类方法返回值类型是int,而子类是double,编译就会报错 。那么向上转型的返回值是怎样的的呢?

//父类
public Animal func(){
    return new Animal("动物");
}

//子类

public Dog func(){
    return new Dog("狗狗·");
}

这样就是方法返回值是向上转型的使用,func()一个方法覆写。

向下转型

需要使用子类独有的方法时使用向下转型,而且向下转型之前一定要先发生向上转型。由于父类不一定是子类的类型,所有向下转型必须要强制类型转换。

什么叫父类不一定是子类的类型呢?上面我们提到dog ia an animal,但是animal is a dog吗,显然不一定。

Animal animal = new Dog();

Dog? dog? =? (dog) animal ;//向下转型

?这里可以发生向下转型的原因是已经发生了向上转型,这个时候就可以使用dog引用去访问Dog类中独有的方法了。

!!要注意,向下转型是有风险的!!

1.如果发生强制转换的两个类之间没有关系,那么一定会出错,例如:

Cat? cat? =? new? Cat() ;? //猫类

Dog? dog? =? (dog) cat ;//编译错误

?上述是强制转换出的错误,两个类之间没有联系,所以编译就会出错

2.现在我们在Dog中写一个方法

public void yell(){ System.out.println("汪汪"); }

yell方法是Dog类独有的,Animal对象要调用就要使用向下转型

Animal animal = new Animal("动物");
       Dog dog1 = (Dog) animal;
       dog1.func();

我们发现编译没有出错,而运行时却出错了,ClassCastException是类型转换异常,大多发生在向下转型时父类引用没有和子类建立联系时。细读代码我们发现animal就是Animal类的对象,没有发生向上转型,所以出错。

instanceof关键字

如何规避向下转型出现错误呢,Java中使用instanceof关键字,它返回一个布尔值,表示一个引用能否指向一个类的实例

if(animal instanceof Dog){
    Dog dog1 = (Dog) animal;
    dog1.yell();
}

?


?

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-01-14 01:50:01  更:2022-01-14 01:50:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:48:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码