重写,多态

重写(覆盖)

子类中有一个方法,与父类中的一个方法,名称、返回类型、参数都一样

PS:1.子类返回类型若是父类返回类型的子类,也定义为重写。如String是Object的子类

         2.子类方法不能缩小父类的访问权限(public -> protected ->默认 -> private),可以扩大

重载就是多个方法同名,但形参不同。

重写为子类与父类方法相同

实例

1.编写一个person类,包含私有属性name,age,构造器,方法say

2.编写一个student类,继承person,增加私有属性,id,score,构造器,定义方法say

3.main方法中分别创建Person和Student对象,调用say方法

Person类

package com.practice;

public class Person {
    private String name;
    private  int age;

    public Person() {
    }

    public Person(String name, int  age) {
        this.name = name;
        this.age = age;
    }
    public String say(){
        return name + age;
    }
}

Student类

package com.practice;

public class Student extends Person{
    private int id;
    private double score;

    public Student() {
    }

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

main方法

package com.practice;

public class test {
    public static void main(String[] args) {
        Person test1 = new Person("jack",10);
        Student test2 = new Student("sad",18,999,15);
        System.out.println(test1.say());
        System.out.println(test2.say());
    }
}

输出结果

多态

  • 多态是同一个行为具有不同的表现形式或形态的能力
  • 同一方法可以根据发送对象的不同而采用不同的行为方式
  • 方法或对象具有多种形态,多态是建立在封装和继承之上的

前提:两个对象(类)存在继承关系

特点

  • 多态成员变量:编译运行看左边
  • 多态成员方法:编译看左边,运行看右边
    
    public class test {
        public static void main(String[] args) {
            Animal one = new Dog();
            System.out.println(one.age);
            one.eat();
        }
    }
    
    class Animal {
        int age = 10;
    
        public void eat() {
            System.out.println("AAA");
        }
    
    }
    
    class Dog extends Animal {
        int age = 20;
        public void eat(){
            System.out.println("BBB");
        }
    }

    输出结果

方法体现多态

public class A {
    public void say(){
        System.out.println("A中的say()被调用");
    }
}


public class B extends A{
    //重载
    public int getSum(int n1,int n2){
        return n1+n2;
    }
    public int getSum(int n1,int n2,int n3){
        return n1+n2+n3;
    }

    //重写

    @Override
    public void say() {
        System.out.println("B中的say()");
    }
}


package com.practice;

public class test {
    public static void main(String[] args) {
        //方法重载体现多态
        B b = new B();
        //传入不同的参数,就会调用不同的sum方法,就体现了多态
        b.getSum(1,2);
        b.getSum(1,2,3);

        //方法重写体现多态
        A a = new A();
        a.say();
        b.say();

    }
}


对象多态(核心)

1.一个对象的编译类型和运行类型可以不一致

父类引用可以指向子类对象

2.编译类型定义对象时就确定,不可改变

3.运行类型可以变化

4.等号左边编译类型,右边运行类型

Animal animal= new Dog();  // 编译类型是Animal,运行类型Dog
animal = new Cat();        //          Animal        Cat
package com.practice;

public class Animal {
    public void cry(){
        System.out.println("哭");
    }
}


public class Dog extends Animal {
 
    public void cry() {
        System.out.println("狗");
    }
}

public class Cat extends Animal{
    @Override
    public void cry() {
        System.out.println("猫");
    }
}


public class test {
    public static void main(String[] args) {
        //对象多态
        //编译类型已经确定  Animal ,对象类型Dog
        Animal animal = new Dog();
        animal.cry();

        //运行类型可变
        //编译类型不可变 Animal,运行类型 Cat
        animal = new Cat();
        animal.cry();
    }
}

例如,存在父类动物,子类猫狗,父类食物,子类骨头,鱼

有一个主人类,存在方法feed(),可以只写一个方法


public void feed(Animal animal,Food food){
}
       Animal animal1 = new Dog();
       Food food1 = new Bone();
       Animal animal2 = new Cat();
       Food food2 = new Fish();

向上转型

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

Animal animal = new Dog();

2.可以调用父类中的所有成员(遵循访问权限),但子类特有成员不可调用

能调用哪些成员,是由编译类型决定的

3.调用方法时,从子类开始查找方法

向下转型

1.子类类型 引用名  = (子类类型) 父类引用;

Dog dog = (Dog) animal;

只能强转父类的引用,不能强转父类的对象

2.父类的引用必须指向的是当前目标类型的对象,比如当前例子,animal不能强转为Cat

3.向下转型后可调用子类特有成员,因为此时,编译类型Dog,运行类型Dog(向下转型就是为了调用特有方法)

注意

1.属性不能重写,直接调用属性时,值看编译类型(与向上转型第二点,调用成员相同)

方法看运行类型

2.instanceof比较操作符,用于判断对象的类型是否为XX类型或XX类型的子类型

public class test1 {
    public static void main(String[] args) {
        BBB  LLL =new BBB();
        System.out.println( LLL instanceof AAA);
        System.out.println( LLL instanceof BBB);
        System.out.println( LLL instanceof CCC);
    }
}
class AAA{}
class BBB extends AAA{}
class CCC extends BBB{}

输出结果

JAVA的动态绑定机制(核心)

1.调用对象方法时,该方法会和该对象的,内存地址/对象类型,绑定

2.调用对象属性时,看编译类型,没有动态绑定机制,哪里声明哪里使用

韩顺平P358

例题,思考二

应用

1.多态数组

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

主要体系,测试类定义数组

Person类

package com.practice;

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    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类

package com.practice;

public class Student extends Person {
    private double score;

    public Student() {
    }

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

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public String say() {
        return super.say() + "\t" + score;
    }
    public void study(){
        System.out.println("study调用");
    }
}

Teacher类

package com.practice;

public class Teacher extends Person{
    private double Salary;

    public Teacher() {
    }

    public Teacher(String name, int age, double salary) {
        super(name, age);
        Salary = salary;
    }

    public double getSalary() {
        return Salary;
    }

    public void setSalary(double salary) {
        Salary = salary;
    }
    public String say() {
        return super.say() + "\t" + Salary;
    }
    public void teach(){
        System.out.println("teach调用");
    }
}

测试类

package com.practice;

public class PloyArray {
    public static void main(String[] args) {
        Person [] persons = new Person[5];
        persons[0] = new Person("王",24);
        persons[1] = new Student("温",23,100);
        persons[2] = new Student("宜",22,80);
        persons[3] = new Teacher("柴",21,5000);
        persons[4] = new Teacher("姬",20,3000);

        //循环遍历多态数组,调用say()
        for (int i = 0; i < persons.length; i++) {
            System.out.println(persons[i].say());
        }
    }
}

输出结果

第二问代码测试类代码

package com.practice;

public class PloyArray {
    public static void main(String[] args) {
        Person [] persons = new Person[5];
        persons[0] = new Person("王",24);
        persons[1] = new Student("温",23,100);
        persons[2] = new Student("宜",22,80);
        persons[3] = new Teacher("柴",21,5000);
        persons[4] = new Teacher("姬",20,3000);

        //循环遍历多态数组,调用say()
        for (int i = 0; i < persons.length; i++) {
            System.out.println(persons[i].say());
            if(persons[i] instanceof Student){
                Student student = (Student) persons[i]; //向下转型
                student.study();
            }
            if(persons[i] instanceof Teacher){
                Teacher teacher = (Teacher) persons[i];
                teacher.teach();
            }
        }
    }
}

输出结果

2.多态参数

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

和上面的,喂养动物实例相同,就不贴详细代码了

    Dog dog = new Dog();
    Bone bone = new Bone();
    Cat cat = new Cat();
    Fish fish = new Fish();
    
    public void FeedAnimal(Animal animal,Food food){
    }

思考

输出结果

1.若Base的display方法改为private,b.display()报错

原因:直接调用属性看编译类型,方法看运行类型,b的编译类型为Base,运行类型为Sub,故运行的是Sub中的display(),

2.我个人还存在一个问题:当Base的display方法改为private,报错理由是Base的display是私有,但应该用的是Sub中的display,原因是,若在Sub中display被重写了,那么通过子类实例向上转型得到的父类引用调用 display 方法时,将根据运行时类型调用相应的重写版本。

直接调用属性时,才看编译类型,此题调用的a.sum()是方法,故用的是B的i值

答案:40,30

输出结果

我是A类

我是B类的有参构造

我是C类的有参构造

我是C类的无参构造

getClass()

Object中的一个方法,用于查看运行类型

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值