首页 > 编程语言 >Java 多态

Java 多态

时间:2023-02-11 18:56:14浏览次数:45  
标签:Java 子类 void 多态 println 类型 public

目录

1、多态的介绍

多态(Polymorphism)按字面意思理解就是“多种形态”,即一个对象拥有多种形态。

即同一种方法可以根据发送对象的不同而采用多种不同的行为方式。

一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多。

多态存在的条件

  • 有继承(基类)或 实现 (接口) 关系
  • 子类重写父类的方法
  • 父类引用变量指向子类对象

注:多态是针对实例方法的多态,不是属性的多态,也不是类方法的多态。

java 引用变量分为两种类型,一种是编译时类型,一种是运行时类型。

编译时类型由声明该变量时使用的类型决定;运行时类型由实际赋值给该变量的对象决定。

如果编译时类型和运行时类型不一致,就可能(重写了方法的话)出现所谓的多态。

class Person {
    public void eat() {	}
}

class Student extends Person {
    // 重写了基类中的方法
    public void eat() {}
    // 子类中特有的方法
    public void study() {}
}

class Applicaton {
	public static void main(String[] args) {
        // 不存在多态 编译时类型和运行时类型一致
        Student s3 = new Student();
        // 不存在多态 编译时类型和运行时类型一致
        Person s2 = new Person();
        
        // 存在多态 编译时类型和运行时类型不一致,重写了基类中的方法
		Person s1 = new Student();
        s1.eat();
        // 报错 原因下方会解释
        // s1.study();
	}
}

当把一个子类对象直接赋值给父类引用变量时:

例如上面的 Person s1 = new Student();

这个 s1 的引用变量的编译类型是 Person,而运行时类型是 Student,当运行时调用该引用变量的方法时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征,这就可能出现:相同类型的变量调用同一个方法时呈现出多种不同的行为特征,这就是多态。

这里的相同类型就是指同一个引用变量(s1),调用同一个方法,但指向不同的子类对象时,表现出不同的行为特征。

注:

1、通过引用变量来直接访问其包含的实例变量时,系统总是试图访问它编译时类型定义的实例变量,而不是运行时类型所定义的实例变量。

2、引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行阶段则可以调用它运行时类型所具有的的方法。

还是上面的例子:Person s1 = new Student(); s1 引用变量只能调用 Person 类的方法,不能直接调用 Student 里独有的方法。

作用

简单来说,就是建立一个父类对象的引用变量,指向不同的子类对象。

把不同的子类对象都当做父类来看待,屏蔽不同子类对象之间的差异,写出通用的代码,以适应需求的不断变化。

而且无论右边 new 的时候换成了哪个子类对象,等号左边的调用方法都不会变化。

2、多态的格式

  • 代码当中体现多态性,其实就是一句话:父类引用指向子类对象
  • 格式:
基类类型 引用变量名称 = new 子类类型(); // 通过继承实现
or
接口类型 引用变量名称 = new 实现类类型(); // 通过接口实现

对象的自动类型

多态的写法其实就是对象的自动类型(类型向上转),只不过是编译器自动完成的。

注:

向上转型一定是成功的,这也证实了子类其实是一种特殊的父类。

这种类型转换只是表明这个引用变量的编译时类型是基类,运行时类型是子类,执行方法时表现的是子类对象的行为方式。

如果想让基类引用变量调用子类中特有的方法,就需要进行强制类型转换。

3、对象的强制类型转换

强制类型转换需要借助于类型转换运算符—— (类型)

类型转换运算符的用法:(类型)变量名称

通过类型转换运算符将一个父类引用变量强转成子类引用变量时,需要注意一下几点:

1、基本类型之间的转换只能在数值类型之间进行。

数值类型:整型(byte、short、int、long)、字符型(char)、浮点型(float、double)。

数值类型和布尔类型之间不能进行类型转换。

2、引用类型之间的转换只能在具有继承 or 实现关系的两个类型之间进行,如果把两个不相关的类型之间进行转换,则会报类型转换异常:ClassCastException

示例

Person s1 = new Student();
// Person 类中没有 study() 方法 进行强制类型转换
((Student) s1).study();

考虑到进行强制类型转换时可能出现的异常,因此进行类型转换之前应先通过 instanceof 运算符来判断是否可以成功转换,避免出现异常,以增强程序的健壮性。

4、instanceof 运算符

使用:A instanceof B

作用:判断其左边对象(指运行时对象)是否为其右边类的实例,返回 boolean 类型的数据。

如果 A 和 B 不存继承话,会出现编译错误。

示例 1:

class Animal {}

class Cat extends Animal {}

class Dog extends Animal  {}

class Applicaton {
	public static void main(String[] args) {
		Animal animal = new Dog();
		if (animal instanceof Dog) {
			System.out.println("汪汪~");
		} else if (animal instanceof Cat) {
			System.out.println("喵喵~");
		}
	}
}

实例 2:

// obj引用变量 编译时类型是 Object,运行时类型是String
// 因为Object是所有类、接口的父类,所以以下才可通过
Object obj = "chatGPT";
// String 是 Object 类的实例
System.out.println(obj instanceof Object);
// String 是 String 类的实例
System.out.println(obj instanceof String);
// String 不是 Math 类的实例
System.out.println(obj instanceof Math);
// String 是 Comparable 接口的实例。接口理解成一种特殊的类
System.out.println(obj instanceof Comparable);

// 注意:这里的 str 没有用多态的写法
String str = "hello";

// 编译不通过,str引用变量编译时类型是String和Math没有继承关系
// System.out.println(str instanceof Math);

// String 对象是 Object 类的实例
System.out.println(str instanceof Object);

5、案例:笔记本USB接口

重点:接口的基本使用、对象的上下转型以及使用接口作为方法的参数。
Computer 使用 USB接口,Mouse、KeyBoards 实现 USB接口

USB 接口

// USB接口类
public interface USB {
    void open();
    void close();
}

Computer 类

// 电脑类
public class Computer {

    public void powerOn(){
        System.out.println("电脑开机");
    }
    public void powerOff(){
        System.out.println("电脑关机");
    }
    // 接口作为方法的参数
    public void useDevice(USB usb){
        usb.open();
        if (usb instanceof Mouse){ // 一定要先判断
            Mouse mouse = (Mouse)usb; // 向下转型
            mouse.click();
        } else if (usb instanceof KeyBoard) {
            KeyBoard keyboard = (KeyBoard)usb;
            keyboard.type();
        }
        usb.close();
    }
}

Mouse 类

// 鼠标类
public class Mouse implements USB{
    @Override
    public void open() {
        System.out.println("打开鼠标");
    }

    @Override
    public void close() {
        System.out.println("关闭鼠标");
    }

    public void click(){
        System.out.println("鼠标点击");
    }
}

KeyBoard 类

// 键盘类
public class KeyBoard implements USB{
    @Override
    public void open() {
        System.out.println("打开键盘");
    }

    @Override
    public void close() {
        System.out.println("关闭键盘");
    }
    public void type(){
        System.out.println("键盘输入");
    }
}

Demo02Main 测试类

public class Demo02Main {
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.powerOn();

        USB usbMouse = new Mouse();
        computer.useDevice(usbMouse);

//        USB usbKeyBoard = new KeyBoard();
        KeyBoard keyBoard = new KeyBoard();
        computer.useDevice(keyBoard);

        computer.powerOff();
    }
}

标签:Java,子类,void,多态,println,类型,public
From: https://www.cnblogs.com/sunzhongjie/p/17112334.html

相关文章

  • javaWeb04-作用域
    本主要讲述javaWeb项目的作用域作用域有:page【前端】,request【请求】,session【会话】,application【项目】主要介绍request,session和application作用域一.request作用域......
  • Javase需要注意的
    byteb=12;System.out.println(b);byteb2=(byte)270;System.out.println(b2);//14(1)a+=b可读性稍差编译效率......
  • Java基础知识点(三元运算符)
    ​三元运算符:​1.需求:定义一个变量记录两个整数的较大值。2.作用:可以进行判断,根据判断的结果得到不同的内容。​3.格式:关系表达式?关系表达式1:关系表达式2;      ......
  • 扫描仪对象 java 230211
    功能接收用户从键盘输入的内容扫描仪的用法......
  • tomcat 应用java8版本的
    jbkjavadevelopmentkitjava开发工具包理论:tomcat原理图container处理请求server8005对服务的开启管理服务HTTP/1.1服务和端口号来自客户端的请求......
  • java中的lambda表达式(从小白也能看懂做起)
    历史背景到目前为止,在Java中传递一个代码段并不容易,不能直接传递代码段,Java是一种面向对象语言,所以必须构造一个对象,这个对象的类需要有一个方法能包含所需的代码但是......
  • Java学习File之案例:递归求阶乘
    packagecom.itheima_111;/*案例:递归求阶乘需求:用递归求5的阶乘,并把结果在控制台输出分析:1.阶乘:一个正整数的阶乘是所有小于及等于该数的正整数的积,自然数n的阶乘写作......
  • "万字" Java I/O 详解
    JavaI/O流讲解每博一文案谁让你读了这么多书,又知道了双水村以外还有一个大世界,如果从小你就在这个天地里,日出而作,日落而息。那你现在就会和众乡亲抱同一理想:经过几年......
  • java——spring boot集成RabbitMQ——MQ简介
    黑马教程入门,连接:https://www.bilibili.com/video/BV15k4y1k7Ep?p=1&vd_source=79bbd5b76bfd74c2ef1501653cee29d6                 ......
  • Java8新特性3-Lambda-内置功能性函数式接口
    比较典型的几个Java8的内置功能性函数式接口在java.util.function包下,主要有四大核心的内置功能型函数式接口:谓词(Predicate)函数(Function)生产者(Supplier)消费者(Cons......