Java多态

一、多态的概念以及分类

概念

简单来说就是多种形态,也就是说同一件事情,发生在不同对象的身上,就会产生不同的结果。比如,同样是吃东西,狗吃骨头,猫吃鱼,蓝胖子爱吃铜锣烧。

分类

静态绑定

静态绑定:也称为前期绑定(早绑定),在编译时,根据用户所传递实参类型就确定了具体调用哪个方法。eg.方法重载

动态绑定

动态绑定:也称为后期绑定(晚绑定),在编译时,不能确定方法的行为,需要等到程序运行时,才能确定具体调用哪个类的方法。

二、多态实现条件

以下条件缺一不可:
1、必须在继承体系下
2、子类必须对父类想要实现多态的方法进行重写
3、通过父类的引用调用重写的方法

多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法

public class Animal {
    String name;
    int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat(){
        System.out.println(name + "吃饭");
    }
}
public class Cat extends Animal{
    public Cat(String name, int age) {
        super(name, age);
    }

   // 快捷键ctrl+o能够重写方法
    @Override
    public void eat() {
        System.out.println(name + "吃鱼");
    }
}
public class Dog extends Animal {
    public Dog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println(name + "吃骨头");
    }
}
public class TestAnimal {

    // 编译时没有任何语法问题,且编译时,形参a不知道将来会指向哪个类的对象;
    // a.eat()不知道要调用哪个类的对象;
    // 程序运行之后形参a引用的具体对象确定后,才知道调用哪个方法
    // 形参类型必须是父类类型
    // 不同对象执行产生的结果是不同的
    public static void eat(Animal a){
        a.eat();
    }

    public static void main(String[] args) {
        Cat cat = new Cat("蓝胖子",1);
        Dog dog = new Dog("来福",3);

        eat(cat);
        eat(dog);

    }
}

运行结果

蓝胖子吃鱼
来福吃骨头

三、重写

重写:也称为覆盖。是子类对父类非静态、非 private 修饰、非 final 修饰、非构造方法等的实现过程进行重新编写。
返回值和形参都不能改变(外壳不变,核心重写)
子类可以根据需要,定义自己特定的行为

重写的规则

1、一般必须与父类方法原型一致:修饰符 返回值类型 方法名(参数列表)要完全一致【参数列表不同是重载】
2、JDK7 以后,被重写的方法返回值类型可以不同,但是必须是具有父子关系的
3、访问权限不能比父类中被重写的方法的访问权限更低
4、父类被 static 、private 修饰的方法、构造方法都不能被重写
5、子类和父类在一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法
6、子类和父类不在一个包中,那么子类只能够重写父类的声明为 public 和protected 的非 final 方法
7、重写的方法,可以使用@Override 注解来显示指定

重写与重载的区别

重载(overload)重写(override)
参数列表必须修改参数列表一定不能修改
返回值类型可以修改返回值类型一定不能修改(父类返回父类的引用,子类返回子类的引用)
访问限定符可以修改访问限定符可以降低限制
异常可以修改异常可以减少或删除,一定不能抛出新的或者更广的异常

方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现

四、向上转型和向下转型

向上转型

向上转型实际就是创建一个子类对象,将其当成父类对象来使用
格式:父类类型 对象名 = new 子类类型();
例:Animal animal = new Cat("蓝胖子",1);
猫和狗都是动物,因此将子类对象转换为父类引用是合理的,大范围可以包含小范围,所以向上转型是安全的;反之,动物不一定是狗,也可以包含猫,企鹅,狐狸等。
优点:让代码更简单灵活
缺点:不能调用到子类特有的方法
【使用场景】
1、方法传参:形参作为父类型的引用,可以接受任意子类的对象

 public static void eat(Animal a){
        a.eat();
    }

2、直接赋值:子类对象赋值给父类对象

Animal animal = new Cat("蓝胖子",1);

3、作为返回值:返回任意子类对象

 public static Animal buyAnimal(String var) {
        if ("狗" == var) {
            return new Dog("狗狗", 2);
        } else if ("猫" == var) {
            return new Cat("猫猫", 1);
        }else{
            return null;
        }
    }

向下转型

向下转型:将父类引用再还原为子类对象
不安全,一旦转换失败,运行时会抛出异常,所以用的不多。

public class TestAnimal {
    public static void main(String[] args) {
    
		// 创建一个对象cat,cat是animal,调用Cat中eat方法
        Cat cat = new Cat("蓝胖子",1);
        Animal animal = cat;
        animal.eat();
        
		// 反之,如果animal不属于Cat,但二者有对应关系,则可以强转为cat,继而调用mew()
        if(cat instanceof Cat){
            cat = (Cat)animal;
            cat.mew();
        }


		// 同上
        Dog dog = new Dog("来福",3);
        animal = dog;
        animal.eat();
        
        if(dog instanceof Dog){
           dog = (Dog) animal;
            dog.bark();
        }

    }
}

运行结果

蓝胖子吃鱼
蓝胖子喵喵~~
来福吃骨头
来福汪汪~~

五、多态的优缺点

优点:

1、能够降低代码的“圈复杂度”,避免使用大量的 if-else
[圈复杂度:循环出现的次数]
2、可扩展能力更强

缺点:代码运行效率低

六、避免在构造方法中调用重写方法

会导致子类对象没有构造完成。

public class Base {
    protected int b = 10;

    public Base() {
        this.func();
    }
    public void func(){
        System.out.println(b);
    }

}
public class Derived extends Base{
    public Derived(){
        super();
        b = 100;
    }

    @Override
    public void func() {
        System.out.println(b);
    }

    public static void main(String[] args) {
        Base b = new Derived();
        b.func();
    }
}

运行结果

10
100
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值