多态的讲解

简介: 多态的讲解

hi,大家好,今天为大家带来多态的讲解


💚💚💚💚1.对于引用的理解

💚💚💚💚2.多态的定义

💚💚💚💚3.多态的实现条件

💚💚💚💚4.重写

💚💚💚💚5.向上转型

💚💚💚💚6.动态绑定

💚💚💚💚7.静态绑定

💚💚💚💚8.向下转型

💚💚💚💚9.多态优缺点

💚💚💚💚9.重写的小点

今天的知识比较多,也会有代码帮助理解


1.为了加深对引用的理解,用一个swap交换函数来帮助理解


class MyValue {
    public int value;
}
public class TestDemo {
    public static void swap(MyValue my1,MyValue my2){
        int tmp= my1.value;
        my1.value=my2.value;
        my2.value=tmp;
    }
    public static void main(String[] args) {
            MyValue myValue1=new MyValue();
        MyValue myValue2=new MyValue();
        myValue1.value  =20;
        myValue2.value=30;
        swap(myValue1,myValue2);
        System.out.println( myValue1.value);
        System.out.println(myValue2.value);
    }
}


运行结果如下

这个代码实现了交换,下面来画图理解一下引用

创建变量,在栈上开辟栈帧,new对象时在堆上



         

2  什么是多态呢???


多态就是多种形态,完成某个行为,最后的结果不尽相同。这个概念比较抽象,下面来举一个例子,相同的食材,给两个不同的人做,两个人做出来的味道是不一样的,比如做番茄炒蛋,有甜口的,还有咸口的,那么这就可以叫做多态,土豆可以做成炸土豆条,炸土豆片,这也是多态


3.多态的实现条件


实现多态需要三个条件

1.继承

2.重写

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

继承在上一篇已经介绍过了,我们现在直接说重写,说到重写,就得说一说重写的条件了


4.重写


1.方法名,返回值,参数列表必须完全一致,返回类型可一样也可不一样,但必须具有父子关系


2.重写又可以称作覆盖,是子类对父类的非静态,非构造,非fianl修饰,非private修饰的方法的重写


3.重写的方法访问修饰符的访问权限要大于等于父类的


4.父类被static、private修饰的方法、构造方法都不能被重写。


5.重写的时候,加上一个@Override注解,帮助我们检查重写的番薯方法是否有问题


下面来一段代码


6.被final 修饰的方法不能被重写,称作密封方法


class Animal{
    public String name;
    public  int age;
    public void eat(){
        System.out.println(name+"正在吃饭");
    }
}
class Dog extends Animal{
    public void wangwang(){
        System.out.println(name+"正在汪汪叫");
    }
    @Override
    public void eat(){
        System.out.println(name+"正在吃狗粮");
    }
}
class Bird extends Animal{
    public String wing;
    public void fly(){
        System.out.println(name+"正在飞");
    }
    public void eat(){
        System.out.println(name+"正在吃鸟粮");
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Animal animal1=new Dog();
        animal1.name="贝贝";
        animal1.eat();
        Animal animal2=new Bird();
        animal2.name="喳喳";
        animal2.eat();
    }
}

52faf5f0816c4ebaa704a839ff4ac730.png


在这段代码中我们可以看到子类重写了父类的eat方法,那么疑问就来了,我们看到引用是父类引用,那么运行结果应该是父类的name,但是父类并没有起名字,所以是null+正在吃饭,那么这就要提到向上转型和动态绑定了


5.向上转型


在重写过程中,我们需要用到动态绑定,因为在第二点提到了是实现多态的第三点是,通过父类引用去调用重写的方法,所以要用到向上转型,向上转型就是从子类到父类,父类的引用指向子类的对象

 

如蓝笔画出来的那个一样,就是向上转型,父类引用指向子类对象


6.动态绑定


什么叫做动态绑定


就是在代码运行的时候很智能的帮我们调用子类中重写的父类方法,在编译的时候它并不能识别出调用哪个方法,但是在运行的时候就可以了,就像上面的代码运行结果一样,new  的是谁,就会调用哪个子类的重写方法


7.静态绑定


与动态绑定相对应得就是静态绑定,静态绑定又叫做早绑定,一般用于重载中,在编译的时候就知道应该执行哪一个方法,当然,在多态中一般是不用得,但是也能用,但是它不安全,一般不敢用,下面来写举个例子


class Animal{
    public String name;
    public  int age;
    public void eat(){
        System.out.println(name+"正在吃饭");
    }
}
class Dog extends Animal{
    public void wangwang(){
        System.out.println(name+"正在汪汪叫");
    }
    @Override
    public void eat(){
        System.out.println(name+"正在吃狗粮");
    }
}
class Bird extends Animal{
    public String wing;
    public void fly(){
        System.out.println(name+"正在飞");
    }
   @Override
    public void eat(){
        System.out.println(name+"正在吃鸟粮");
    }
}
class Cat extends Animal{
    public void miaomiao(){
        System.out.println(name+"正在喵喵叫");
    }
    @Override
    public void eat() {
        System.out.println(name+"正在吃猫粮");
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Animal animal=new Dog();
        Dog dog=(Dog)animal;
        dog.name="贝贝";
        dog.eat();
        dog.wangwang();
        System.out.println("=======");
        Cat  cat=(Cat)animal;
        cat.eat();
        cat.miaomiao();
    }
    public static void mai1(String[] args) {
        Animal animal1=new Dog();
        animal1.name="贝贝";
        animal1.eat();
        Animal animal2=new Bird();
        animal2.name="喳喳";
        animal2.eat();
        Animal  animal3=new Cat();
        animal3.name="小花";
        animal3.eat();
    }
}


这个就是向下转型,很不安全,如下图,子类引用指向父类对象,报错了

 但是有方法防止报错,使用库提供的instanceof函数,,现在对这个代码进行改良

这句话的意思是判断子类对象指向的引用是否包含Cat类,这样就不会报错了,但我们还是不提倡这样写


9.多态的优缺点


优点:能够降低代码的 "圈复杂度", 避免使用大量的 if - else


多态缺点


父类的属性不能重写,父类的构造方法不能重写


当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性

10.重写的小点


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


class B {
    public B() {
        // do nothing
        func();
}
    public void func() {
        System.out.println("B.func()");
    }
}
class D extends B {
    private int num = 1;
    public D () {
        super();
    }
    @Override
    public void func() {
        //System.out.println("fafdadssa!!!!!");
        System.out.println("D.func() " + num+" 因为父类此时还没有走完!");
    }
}
public class Test4 {
    public static void main(String[] args) {
        D d = new D();
    }
}


当大家看到这段代码的时候大家觉得结果是几,一定有人以为是1,大漏特漏!!!

运行他看看

看,结果是0,为啥呢,因为父类都没有构造完成,所以不能到子类那一步,不要写这种代码,有坑,大家避雷!!!

下面写一个图形类的代码加深大家对多态的理解


class Shape {
    public void draw() {
        System.out.println("画图形!");
    }
}
class Rect extends Shape {
    @Override
    public void draw() {
        System.out.println("画矩形!");
    }
}
class Cycle extends Shape {
    @Override
    public void draw() {
        System.out.println("画圆!");
    }
}
class Flower extends Shape {
    @Override
    public void draw() {
        System.out.println("❀!");
    }
}
public class Test3 {
    public static void drawMap(Shape shape) {
        shape.draw();
    }
    public static void drawMap() {
        Rect rect = new Rect();
        Cycle cycle = new Cycle();
        Flower flower = new Flower();
        Shape[] shapes = {cycle,rect,cycle,rect,flower};
        //int[] array = {1,2,3,4};
        for(Shape shape : shapes) {
            shape.draw();
        }
    }
  /*  public static void drawMap3() {
        Shape rect = new Rect();
        Shape cycle = new Cycle();
        Shape flower = new Flower();
        Shape[] shapes = {cycle,rect,cycle,rect,flower};//这里完成了向上转型!!!,和上面的写法其实是一样的
        //int[] array = {1,2,3,4};
        for(Shape shape : shapes) {//for  each 遍历
            shape.draw();
        }
    }
*/
    public static void main(String[] args) {
        drawMap();
        //drawMap2() ;
        /*Rect rect = new Rect();
        Cycle cycle = new Cycle();
        drawMap(rect);
        drawMap(cycle);
        drawMap(new Flower());*/
    }
}


向上转型有三种方式

1.直接赋值

2.方法传参

3.方法返回值

显然上述代码用的是方法传参

好了,今天的讲解就到此结束,下一期为大家带来抽象类和接口!!!

886!!!🎉🎉🎉👀👀👀

备注:抽象类小部分知识在11.13日笔记

相关文章
|
3天前
|
存储 编译器 数据安全/隐私保护
【C++】多态
多态是面向对象编程中的重要特性,允许通过基类引用调用派生类的具体方法,实现代码的灵活性和扩展性。其核心机制包括虚函数、动态绑定及继承。通过声明虚函数并让派生类重写这些函数,可以在运行时决定具体调用哪个版本的方法。此外,多态还涉及虚函数表(vtable)的使用,其中存储了虚函数的指针,确保调用正确的实现。为了防止资源泄露,基类的析构函数应声明为虚函数。多态的底层实现涉及对象内部的虚函数表指针,指向特定于类的虚函数表,支持动态方法解析。
11 1
|
3月前
|
Java
多态
多态的基本认识
|
5月前
|
编译器 C++ p3c
【c++】多态
【c++】多态
25 0
|
6月前
深入理解多态
深入理解多态
多态你真的了解吗?
多态你真的了解吗?
72 0
|
6月前
|
存储 C++
C++:多态
C++:多态
46 0
|
6月前
|
存储 编译器 C++
|
6月前
|
存储 编译器 C++
C++【多态】
C++【多态】
66 0
|
编译器 C++
多态(C++)上
多态(C++)
44 0
|
编译器
多态的初识
多态的初识