java多态进阶,吃透多态,这一篇就够了

简介: 1.动态绑定机制java的动态绑定机制非常重要🎈实例A我们来看一个实例:


1.动态绑定机制


java的动态绑定机制非常重要🎈


实例A


我们来看一个实例:



阅读上面的代码,请说明下面的程序将输出什么结果:



程序将会输出40和30,这个实例很简单,直接看运行类型即可,该代码的运行类型为B,所以会调用B类的方法


实例B


我们将上面的代码变通一下,将子类中的如下代码块注销:



随后继承机制会访问父类的sum方法:



那么这里有一个问题,此处的getI(),会执行子类的还是父类的呢?


当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定🚀


代码的运行类型依然是B,所以此处会执行子类的getI()方法,结果输出为30


实例C


现在我们再变通以下上面的代码


再将子类中如下的代码块注销:



继承机制会执行父类的sum1方法:



那么这里有一个问题,此处的i,会使用子类的还是父类的呢?

属性没有动态绑定机制,哪里声明,哪里使用(使用当前类的)🐱‍🏍

此处的i在父类进行声明,所以会选用父类的i属性,结果为20


2.多态数组


定义:

数组的定义类型为父类类型,但是保存的实际元素类型为子类类型

Person父类:


/**
 * 多态数组父类
 */
public class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String say() {
        return name + '\t' + age;
    }
}


Student子类:


/**
 * 多态数组学生子类
 */
public class Student extends Person{
    private double score;
    public Student(String name, int age, double score) {
        super(name, age);
        this.score = score;
    }
    // 重写父类的say方法
    public String say() {
        return super.say() + '\t' + score;
    }
}


Teacher子类:


/**
 * 多态数组教师子类
 */
public class Teacher extends Person {
    private double sal;
    public Teacher(String name, int age, double sal) {
        super(name, age);
        this.sal = sal;
    }
    public double getSal() {
        return sal;
    }
    public void setSal(double sal) {
        this.sal = sal;
    }
    public String say() {
        return super.say() + '\t' + sal;
    }
}


测试多态数组的使用:


public class Test {
    public static void main(String[] args) {
        // 多态数组的使用
        Person[] persons = new Person[5];
        persons[0] = new Person("dahe",20);
        persons[1] = new Student("wangwei",11,100);
        persons[2] = new Student("zhangsan",12,60);
        persons[3] = new Teacher("wang",33,15000);
        persons[4] = new Teacher("li",55,25000);
        // 循环遍历多态数组,调用say方法
        for (int i = 0; i < persons.length; i++) {
            String out = persons[i].say(); // 动态绑定机制,编译类型永远都是Person
            // 运行类型是根据实际情况由JVM机决定
            System.out.println(out);
        }
    }
}
----------------------------------
输出:
dahe  20
wangwei 11  100.0
zhangsan  12  60.0
wang  33  15000.0
li  55  25000.0


3.多态数组的高阶用法


现在,教师子类新增了教学方法:


public void teach() {
    System.out.println("老师:" + getName() + "正在讲课!");
}


学生子类新增了学习方法:


public void study() {
    System.out.println("学生:" + getName() + "正在学习!");
}


那么,有没有办法通过多态数组来访问他们子类对应的独有的方法呢?事实上,可以通过巧妙使用instanceof来解决:

变通一下,改变多态数组的循环操作:


// 循环遍历多态数组,调用say方法
for (int i = 0; i < persons.length; i++) {
    String out = persons[i].say(); // 动态绑定机制,编译类型永远都是Person
    // 运行类型是根据实际情况由JVM机决定
    System.out.println(out);
    if (persons[i] instanceof Student) {
        // 向下转型
        Student student = (Student) persons[i];
        student.study();
    } else if (persons[i] instanceof Teacher) {
        Teacher teacher = (Teacher) persons[i];
        teacher.teach();
    }
}
-----------------------------
输出:
dahe  20
wangwei 11  100.0
学生:wangwei正在学习!
zhangsan  12  60.0
学生:zhangsan正在学习!
wang  33  15000.0
老师:wang正在讲课!
li  55  25000.0
老师:li正在讲课!


大功告成!多态数组即强大又完美!🎂


4.多态参数


方法定义的形参类型为父类类型,实参类型允许为子类类型

接下来我们来演示以下多态参数的使用:

父类:


/**
 * 多态参数 - 父类
 */
public class Employee {
    private String name;
    private double sal;
    public Employee(String name, double sal) {
        this.name = name;
        this.sal = sal;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getSal() {
        return sal;
    }
    public void setSal(double sal) {
        this.sal = sal;
    }
    // 得到年工资的方法
    public double getAnnual() {
        return 12 * sal;
    }
}


员工子类:


/**
 * 多态参数 - 子类员工
 */
public class Worker extends Employee{
    public Worker(String name, double sal) {
        super(name, sal);
    }
    public void work() {
        System.out.println("普通员工:" + getName() + "正在工作!");
    }
    public double getAnnual() {
        return super.getAnnual();
    }
}


经理子类:


/**
 * 多态参数 - 经理子类
 */
public class Manager extends Employee{
    private double bonus; // 奖金
    public Manager(String name, double sal, double bonus) {
        super(name, sal);
        this.bonus = bonus;
    }
    public double getBonus() {
        return bonus;
    }
    public void setBonus(double bonus) {
        this.bonus = bonus;
    }
    public void manage() {
        System.out.println("经理:" + getName() + "正在管理!");
    }
    @Override
    public double getAnnual() {
        return super.getAnnual() + bonus;
    }
}


我们来测试一下,求不同岗位的雇员的年薪:


/**
 * 多态参数测试类
 */
public class Test {
    public static void main(String[] args) {
        Worker zhang = new Worker("张工",1000);
        Manager milan = new Manager("milan", 5000, 2000);
        Test test = new Test();
        test.showEmpAnnual(zhang);
        test.showEmpAnnual(milan);
    }
    // 获取员工的年薪,采用多态参数
    public void showEmpAnnual(Employee e) {
        System.out.println(e.getAnnual());
    }
}
-------------------------------------
输出:
12000.0
62000.0


5.多态参数的高阶用法


我们来对上面的多态参数代码做一个完善,如果传入的是员工,则调用自己的work方法,如果传入的是经理,则调用自己的manage方法

增加一个下面的方法:


public void testWork(Employee e) {
    if (e instanceof Worker) {
        ((Worker) e).work(); // 向下转型
    } else if (e instanceof Manager) {
        ((Manager) e).manage();
    }
}


测试:


test.testWork(zhang);
test.testWork(milan);
---------------------------
输出:
普通员工:张工正在工作!
经理:milan正在管理!


成功之秘诀,在始终不变其目的🌕

目录
相关文章
|
9天前
|
Java 数据挖掘 开发者
Java网络编程进阶:Socket通信的高级特性与应用
【6月更文挑战第21天】Java Socket通信是分布式应用的基础,涉及高级特性如多路复用(Selector)和零拷贝,提升效率与响应速度。结合NIO和AIO,适用于高并发场景如游戏服务器和实时数据分析。示例展示了基于NIO的多路复用服务器实现。随着技术发展,WebSockets、HTTP/2、QUIC等新协议正变革网络通信,掌握Socket高级特性为应对未来挑战准备。
|
5天前
|
Java 机器人 程序员
深入理解Java中的类与对象:封装、继承与多态
深入理解Java中的类与对象:封装、继承与多态
|
7天前
|
缓存 安全 小程序
从基础到进阶:掌握Java中的Servlet和JSP开发
【6月更文挑战第23天】Java Web开发中的Servlet和JSP是关键技术,用于构建动态网站。Servlet是服务器端小程序,处理HTTP请求,生命周期包括初始化、服务和销毁。基础Servlet示例展示了如何响应GET请求并返回HTML。随着复杂性增加,JSP以嵌入式Java代码简化页面创建,最佳实践提倡将业务逻辑(Servlet)与视图(JSP)分离,遵循MVC模式。安全性和性能优化,如输入验证、HTTPS、会话管理和缓存,是成功应用的关键。本文提供了一个全面的学习指南,适合各级开发者提升技能。
|
6天前
|
安全 Java
深度解读Java的继承和多态的特性
深度解读Java的继承和多态的特性
|
9天前
|
Java 编译器
Java多态(如果想知道Java中有关多多态的知识点,那么只看这一篇就足够了!)
Java多态(如果想知道Java中有关多多态的知识点,那么只看这一篇就足够了!)
|
5天前
|
设计模式 Java 容器
Java进阶 - 黑马
Java进阶 - 黑马
9 1
|
11天前
|
Java 开发者 UED
【实战攻略】Java异常处理进阶:throw关键字,打造坚不可摧的错误防御体系!
【6月更文挑战第19天】在Java中,`throw`关键字用于主动抛出异常,特别是在检测到错误条件如非法参数时。通过`throw`,开发者能控制何时中断程序并提供清晰的错误信息。例如,在验证订单金额时,如果金额小于等于零,可以抛出`IllegalArgumentException`。此外,`throw`还可用于构建异常链,保留错误上下文,便于问题追溯。掌握`throw`使用,是构建健壮异常处理和提升用户体验的关键。
|
9天前
|
机器学习/深度学习 Java Serverless
Java开发者的神经网络进阶指南:深入探讨交叉熵损失函数
今天来讲一下损失函数——交叉熵函数,什么是损失函数呢?大体就是真实与预测之间的差异,这个交叉熵(Cross Entropy)是Shannon信息论中一个重要概念,主要用于度量两个概率分布间的差异性信息。在信息论中,交叉熵是表示两个概率分布 p,q 的差异,其中 p 表示真实分布,q 表示预测分布,那么 H(p,q)就称为交叉熵:
|
11天前
|
Java 数据安全/隐私保护
Java基础之类封装、继承、多态
Java基础之类封装、继承、多态
11 2
|
11天前
|
安全 Java 数据安全/隐私保护
Java基础之类封装、继承、多态
Java基础的封装、继承和多态是OOP的核心。封装通过访问控制(如private)隐藏类的内部细节,提供公共接口供外部交互。例如,`Person`类封装`name`和`age`,通过`getName()`和`setAge()`方法访问。继承允许子类(如`Dog`)继承父类(如`Animal`)的属性和方法,并可扩展或覆盖。多态使得父类引用可指向子类对象,调用方法时根据实际对象类型执行,如不同动物的`makeSound()`。接口实现多态提供了一种定义行为而不必关心实现的方式。向上转型(子类→父类)安全且默认,而向下转型(父类→子类)需类型检查以避免异常。
11 1