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知识库]第四章:多态与动态绑定机制

多态

多态:方法或对象具有多种形态。多态是建立在封装和继承基础之上

代码演示:方法的多态

sum方法实现了重载,method方法实现了重写;相同名称的方法有着不同的作用(形态)

public class Test {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        a.method();     // 运行结果:父类的成员方法
        b.method();     // 运行结果:子类的成员方法
        System.out.println(b.sum(2,3));      // 运行结果:5
        System.out.println(b.sum(2,3,3));    // 运行结果:8
    }
}
class A {
    public void method() {
        System.out.println("父类的成员方法");
    }
}
class B extends A {
    @Override
    public void method() {
        System.out.println("子类的成员方法");
    }
    public static int sum(int num1,int num2) {
        return num1+num2;
    }
    public static int sum(int num1,int num2,int num3) {
        return num1+num2+num3;
    }
}

对象的多态

对象多态的特点
	1. 一个对象的编译类型与运行类型不同
	2. 等号的左边是编译类型,等号的右边是运行类型
	3. 运行期类型可能会发生变化

代码演示:对象的多态

同一个对象可以是Dog类,也可以是Cat类

public class Test {
    public static void main(String[] args) {
        // animal编译类型是Animal,运行类型是Dog
        Animal animal = new Dog();  
        animal.eat();
        // animal运行类型是Cat
        animal = new Cat();
        animal.eat();
    }
}
class Animal {                                                                                                                                                                                                                               
    public void eat() {
        System.out.println("动物吃食物");
    }
}
class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}
class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

向上造型

1. 向上造型的本质:父类的引用指向子类的对象

2. 向上造型的语法:父类类型 引用名 = new 子类类型();

3. 向上造型的特点
	a. 可以调用父类中所以成员(需遵守访问权限)
	b. 不可以调用子类的特有的成员
	c. 最终运行结果由子类的具体实现

注意:属性没有重写之说,属性的值由编译类型决定

代码演示:向上造型

public class Test {
    public static void main(String[] args) {
        // animal编译类型是Animal,运行类型是Dog
        Animal animal = new Dog();
        animal.eat();       // 运行结果:狗吃肉
        animal.sleep();     // 运行结果:动物睡觉觉
        
        // 注意:animal对象无法访问子类的特有的方法run()
    }
}

class Animal {
    public void sleep() {
        System.out.println("动物睡觉觉");
    }

    public void eat() {
        System.out.println("动物吃食物");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }

    public void run() {
        System.out.println("狗在跑步");
    }
}

向下转型

1. 向下转型的语法:子类类型 引用名 = (子类类型) 父类引用;

2. 向下转型的特点
	a. 只能强转父类的引用,不能强转父类的对象
	b. 要求父类引用必须指向的是当前目标类型的对象
	c. 当向下转型后,可以调用子类类型中的所有成员

代码演示:向下转型以及instanceof关键字

public class Test {
    public static void main(String[] args) {
        // animal编译类型是Animal,运行类型是Dog
        Animal animal = new Dog();

        /**错误示范
            Cat cat = (Cat) animal; 程序报错:ClassCastException(类转换异常)
            为了解决在编译期确保类的成功转换,我们可通过instanceof关键字
            先判断类型转换异常,再执行转换

         */
        if(animal instanceof Cat) {
            Cat cat = (Cat) animal;
            cat.work();
        }else {
            Dog dog = (Dog) animal;
            dog.work();
            dog.eat();
            dog.sleep();
        }
    }
}

class Animal {
    public void sleep() {
        System.out.println("动物睡觉觉");
    }

    public void eat() {
        System.out.println("动物吃食物");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }

    public void work() {
        System.out.println("狗在看大门");
    }
}

class Cat extends Animal {
    public void work() {
        System.out.println("猫在捉老鼠");
    }
}

自我总结:向上转型与向下转型的区别

格式的区别
	向上造型:父类类型 引用名 = new 子类类型();
	向下转型:子类类型 引用名 = (子类类型) 父类的引用名;

访问的区别
	向上造型:“除”子类特有的成员都能访问
	向下转型:父子类的成员都能访问
	(注意:权限修饰符)

Java的动态绑定机制

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

当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用

代码演示:动态绑定机制

public class Test {
    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.sum());    // 运行结果:60
        /** a.sum() 的动态绑定机制
         *  对于调用方法,优先调用运行期类型中的方法(getI())
         */
        System.out.println(a.sum1());   // 运行结果:40
        /** a.sum1() 的动态绑定机制
         *  对于调用属性,没有绑定机制这么一说,直接调用A类的变量i
         */
    }
}
class A {
    public int i = 10;
    public int getI() {
        return i;
    }
    public int sum() {
        return getI() + 40;
    }
    public int sum1() {
        return i + 30;
    }
}
class B extends A {
    public int i = 20;
    public int getI() {
        return i;
    }
}

代码演示:多态数组

代码将近百行,里面写了哪些内容呢???
1. 四个类:父类Person、子类Student和Teacher以及测试类(两个子类都继承了父类)
2. 父类具有姓名与年龄的共同属性,学生类与老师类分别具有分数与薪资的特有属性
3. 创建多态数组,通过向上造型的方式将每个对象的属性进行赋值并访问
4. 通过向下转型的方式将访问运行类型特有的成员方法
public class Test {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("赵四", 23);
        persons[1] = new Student("小华", 23, 100);
        persons[2] = new Student("小明", 12, 10);
        persons[3] = new Teacher("老张", 28, 3000);
        persons[4] = new Teacher("老陈", 26, 2000);
        for (int i = 0; i < persons.length; i++) {
            System.out.println(persons[i].say());
            if (persons[i] instanceof Student) {
                Student s = (Student) persons[i];	// 先向下转型
                s.study();							// 再调用方法
            } else if (persons[i] instanceof Teacher) {
                ((Teacher) persons[i]).teach();		// 一步到位
            } else if (persons[i] instanceof Person) {
            } else {
                System.out.println("类型有误,自行解决");
            }
        }
    }
}

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 int getAge() {
        return age;
    }

    public String say() {
        return getName() + "\t" + getAge();
    }
}

class Student extends Person {
    private double score;

    public Student(String name, int age, double score) {
        super(name, age);
        this.score = score;
    }

    public double getScore() {
        return score;
    }

    @Override
    public String say() {
        return "学生" + super.say() + " 分数:" + getScore();
    }

    public void study() {
        System.out.println("学生 " + getName() + "在学java...");
    }
}

class Teacher extends Person {
    private int salary;

    public Teacher(String name, int age, int salary) {
        super(name, age);
        this.salary = salary;
    }

    public int getSalary() {
        return salary;
    }

    @Override
    public String say() {
        return "老师 " + super.say() + " 薪资:" + getSalary();
    }

    public void teach() {
        System.out.println("老师:" + getName() + ",在教java...");
    }
}

代码演示:多态参数

多态数组:方法定义的形参类型是父类类型,实参类型是子类类型

将近百行代码,里面写了哪些内容呢???
1. 一共有四个类分别是父类(Employee),子类(Manager、Worker),测试类(Test)
2. 员工类的私有属性name和salary,计算年工资getAnnual方法
3. 经理类特有属性奖金bonus和管理manage方法
4. 员工类特有方法work
5. 测试类中有showEmpAnnal(Employee e)的方法,获取员工的年薪
6. 测试类中另一个testWork(Employee e)的方法,分别调用经理的管理方法和员工工作的方法

对于个人易错点,没有将56理解清楚,导致无法以向上造型与向下转型的方式进行调用方法
public class Test {
    public static void main(String[] args) {
        Worker worker = new Worker("强哥", 3000);
        Manager manager = new Manager("小赵", 20000, 6000);
        Test test = new Test();
        test.showEmpAnnual(worker);				// 实参是子类类型
        test.showEmpAnnual(manager);
        test.testWork(worker);
        test.testWork(manager);
    }

    public void showEmpAnnual(Employee e) {		// 方法的形参是父类类型
        System.out.println(e.getAnnual());
    }

    public void testWork(Employee e) {
        if (e instanceof Worker) {
            ((Worker) e).work();
        } else if (e instanceof Manager) {
            ((Manager) e).work();
        } else {
            System.out.println("对象有误");
        }
    }
}

class Employee {
    private String name;
    private int salary;

    public Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public int getSalary() {
        return salary;
    }

    public int getAnnual() {
        return getSalary() * 12;
    }
}

class Worker extends Employee {
    public Worker(String name, int salary) {
        super(name, salary);
    }

    public void work() {
        System.out.println("工人:" + getName() + ",正在搬砖");
    }

    @Override
    public int getAnnual() {
        return super.getAnnual();
    }
}

class Manager extends Employee {
    private int bonus;

    public Manager(String name, int salary, int bonus) {
        super(name, salary);
        this.bonus = bonus;
    }

    public int getBonus() {
        return bonus;
    }

    public void work() {
        System.out.println("经理:" + getName() + ",正在监工");
    }

    @Override
    public int getAnnual() {
        return super.getAnnual() + getBonus();
    }
}

`

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:21:19  更:2022-03-24 00:21:53 
 
开发: 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 6:51:19-

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