【Java】多态

目录

1.多态的概念

2.多态实现的条件

3.重写

4.向上转移和向下转型

4.1向上转型

4.2向下转型

5.多态的优缺点

5.1多态的优点

5.2多态的缺点

6.避免在构造方法中调用重写的方法


1.多态的概念

多种形态,也就是说去完成某个行为,当不同的对象去完成时会产生不同的状态。

同一间事情,发生在不同的对象身上,就会产生不同的结果。

2.多态实现的条件

1.必须在继承体系下

2.子类必须要对父类中方法进行重写

3.通过父类的引用调用重写的方法

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

3.重写

外壳不变,内容核心重新写。

1.方法名相同

2.参数列表相同【顺序、个数类型】

3.返回值相同

tip:被final,static,private修饰的方法不可以被重写

@override 注解,重写

子类重写父类方法时,子类的方法访问修饰限定符>=父类

重写与重载的区别:
 

区别点重写重载
参数列表一定不能修改必须修改
返回类型一定不能修改【除非可以构成父类关系】可以修改
访问限定符一定不能做更严格的限制(可以降低限制)可以修改

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

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

tip:编译的时候确实是调用了父类eat的方法,运行的时候绑定到了子类。

4.向上转移和向下转型

4.1向上转型

创建一个子类对象,将其当成父类对象来使用。

语法:父类类型 对象名 = new 子类类型( );

Animal animal = new Cat("小宝",2);

使用场景:

1.直接传参

2.方法传参

3.方法返回

public class TestPeaple {
    //2.方法传参:形参为父类型引用,可以接收任意子类的对象
    public static void eats(Peaple p) {
        p.eat();
    }

    //3.做返回值:返回任意子类的对象
    public static Peaple peapleA(String var) {
        if ("nan".equals(var)) {
            return new Men("nan", 4);
        } else if ("nv".equals(var)) {
            return new Women("nv",5);
        }else {
            return null;
        }
    }

    public static void main(String[] args) {
        //1.直接赋值:子类对象赋值给父类对象
        Peaple men = new Men("小李",10);
        Peaple women = new Women("小王",10);
        eats(men);
        eats(women);
        Peaple peaple = peapleA("nan");
        peaple.eat();
        peaple = peapleA("nv");
        peaple.eat();
    }

}

优点:让代码实现更加简单灵活。
缺点:不能调用到子类特有的方法。

4.2向下转型

将一个子类对象经过向上转型之后当成父类方法使用,再也没有办法调用子类的方法,但有时可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。

编译报错是因为Peaple中没有sports方法,men里面有。所以就要用到向下转型,调用子类方法。

报错的原因是因为Peaple指向的是men,不是women。为了提高向下转型的安全性,引入了instanceof,如果该表达式为true,则可以安全转换。

5.多态的优缺点

5.1多态的优点

class Rect extends Shap{
    @Override
    public void draw(){
        System.out.println("菱形");
    }

}
class Cycle extends Shap{
    @Override
    public void draw(){
        System.out.println("⭕");
    }
}
class Flower extends Shap{
    @Override
    public void draw(){
        System.out.println("花朵");
    }
}

1.能够降低代码的“圈复杂度”(描述一个代码复杂程度的方式,一个代码如果有很多条件分支语句或者有很多循环语句,就认为理解起来复杂),避免使用大量的if-else

public class drawShapes {
    public static void main(String[] args) {
        Rect rect = new Rect();
        Cycle cycle = new Cycle();
        Flower flower = new Flower();
        String[] shapes = {"Cycle", "Rect", "Rect", "Flower"};
        for (String shape : shapes) {
            if (shape.equals("Cycle")) {
                cycle.draw();
            }else if(shape.equals("Flower")){
                flower.draw();
            }else if(shape.equals("Rect")){
                rect.draw();
            }
        }
    }
}

复杂度高。

public class drawShapes {
    public static void main(String[] args) {
        Shap rect = new Rect();
        Shap cycle = new Cycle();
        Shap flower = new Flower();
        //向上转型
        Shap[] shapes = {cycle,rect,flower,rect};
        for (Shap shape:shapes) {
            shape.draw();
        }
    }
}

复杂度低

2.可拓展性更强。

如果新增加一种形状,使用多态的方式代码改动成本也比较低。

class tree extends Shap{
    @Override
    public void draw(){
        System.out.println("树木");
    }
}

5.2多态的缺点

代码的运行效率降低。

1.属性没有多态性:当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性。

2.构造方法没有多态性。

6.避免在构造方法中调用重写的方法


    class A{
        public A(){
        func();
        }
        public void func() {
            System.out.println("A.func");
        }
    }

    class B extends A {
        private int num = 1;

        @Override
        public void func() {
            System.out.println("B.func()" + num);
        }
    }
    public class Test {
        public static void main(String[] args) {
            B b = new B();
        }
    }

为什么会是0呢?

调用B对象时,调用了A的构造方法,A的构造方法中调用了func()方法,此时触发了动态绑定,会调用到B中的func,此时D对象分配了内存空间,但是自身没有被初始化,值为0.

tip:所以在构造方法中,尽量避免使用实例方法,除了final和private方法。

  • 30
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值