【Java】面向对象的特征之一(下):多态

目录

多态

1.什么是多态?

2.多态的实现条件

3.多态的优缺点

向上转型和向下转型

向上转型

1.向上转型的理解

2.向上转型格式

3.向上转型的实现方式

1.直接赋值

2.方法的传参

3.返回值 

4.向上转型的优缺点

向下转型

1.向下转型的理解

2.向下转型的格式

3.向下转型的实现方式

重写

1.重写的概念

2.重写的作用

3.重写的格式

什么是动态绑定?

什么是静态绑定? 

4.重写与重载的区别

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


多态

1.什么是多态?

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

2.多态的实现条件

  1. 必须在继承体系下(继承);
  2. 子类必须要对父类中的方法进行重写(重写);
  3. 通过父类的引用调用重写的方法(向上转型)。 

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

可能刚开始看这张图片不是很能理解,接下来会进行对向上转型和重写的讲解,看完在回头看这张代码,我相信你能更清晰的理解他们。 

3.多态的优缺点

优点:

  • 能够降低代码的“圈复杂度”,避免大量使用if—else
  • 扩展能力强,改动成本低 

缺点:

  •  代码的运行效率低

向上转型和向下转型

向上转型

1.向上转型的理解

向上转型:实际就是创建一个子类对象,将其当成父类对象来使用 

2.向上转型格式

父类类型 对象名 =new 子类类型 

3.向上转型的实现方式

1.直接赋值

public class Test {
    public static void main(String[] args) {
        Animal animal=new Dog(2,"小乖");      
    }

2.方法的传参

public static void main(String[] args) {
        Dog dog = new Dog(2,"小乖");
        func(dog);
    }
    public static void func(Animal animal){
    }

3.返回值 

public static void main(String[] args) {
        Animal animal=func2();
    }
    public static Animal func2(){
        Dog dog = new Dog(2,"小乖");
        return dog;
    }

4.向上转型的优缺点

优点:让代码实现更简单灵活;

缺点:通过父类的引用,调用父类是无法直接调用的,只能调用父类自己的。 

向下转型

1.向下转型的理解

向下转型:将父类引用在还原为子类对象

2.向下转型的格式

子类类型 类型名=(子类类型)父类类型名; 

3.向下转型的实现方式

 先通过向上转型,在进行强制类型转换

由上述代码,可以得出,向上转型是向下转型的基础。   

如果我在加一个父类的子类猫类。先将狗向上转型为动物,再将其向下转型为猫类,这样是否可以?

结果告诉我们不是所有的向下转型都可以的 

上面两种的区别就是,一个本身就是Dog,而另一个是Dog不是Cat。 

为了预防这种情况,我们可以使用instanceof来验证

instanceof是引用的意思 

    public static void main(String[] args) {
        Animal animal1=new Dog(3,"小黄");
        if(animal1 instanceof Cat){
            System.out.println("引用了猫");
        }
        else{
            System.out.println("没有引用");
        }

重写

1.重写的概念

重写:也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写。可以理解为子类对父类方法的覆盖。

2.重写的作用

  • 子类能够根据需要实现父类的方法

3.重写的格式

  1. 子类和父类的两个方法名相同;
  2. 子类和父类的参数列表相同(个数,顺序,类型);
  3. 子类和父类的返回值要相同; 

如果我们调用animal的fun,其结果又是什么? 

我们发现他调用的是子类的重写的方法,这种叫做动态绑定。

什么是动态绑定?

动态绑定:在继承的情况下,当代码运行的时候,通过父类引用,调用父类和子类的重写的方法,结果实际调用了子类的方法。 

注意事项:

  •  虽然说,重写的时候,子类和父类的方法返回值类型、方法名、参数列表要完全一致,但是被重写的方法返回值类型也可以不同,但是其返回值类型要保持父子关系

既然有了动态绑定,那么应该也有静态绑定吧。

什么是静态绑定? 

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

    public static void main(String[] args) {
        int a=1;
        int b=2;
        int c=3;
        int ret=add(a,b);
        System.out.println(ret);//3
    }
    public static int add(int a,int b){
       return a+b;
    }
    public static int add(int a,int b,int c){
        return a+b+c;
    }

调用几个参数,你就知道用确定了调用的是那个方法 

  • 重写的时候,可以使用@Override注解来起提示作用,如果你的重写方法是错的,那么编译器会报错;注意这里的@Override是写在子类重写父类的方法上面,而不是父类方法上方。

  • 在重写中,子类的重写方法的访问权限不能比父类中被重写的方法,并且不能使用private访问权限符。如果你在子类的访问权限符是protected,而父类却是public,那么将会报错,可以将public改成比protected访问权限低的default。

  

  • 不能被final修饰,如果被final修饰,这意味着该父类不能被重写(密封方法)

  •  不能使用静态方法

4.重写与重载的区别

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

什么时候使用重写?

对于已经投入使用的类,进行不要修改。最好的方式就是:重新定义一个新的类,来重复利用其中共性的内容并添加或改动新的内容。例如:软件的功能的改进,我们不在原来老的类进行改进,因为原来的软件,用户还在使用。于是我们新建一个类,对这个改进的方面进行重写就好了

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

为什么这么说呢?

1.首先我构建了一个父类Animal和子类Dog,在父类和子类写了fun()重写方法并在父类的构造方法中调用了子类和父类的重写方法。实例化后,我得出的结果是父类的被重写方法还是子类对父类的重写方法?我在父类的构造方法中调用父类的方法,结果应该是调用父类的方法吧。

但结果是子类的构造方法 

2.既然我都知道了,在父类构造方法中调用子类和父类的重写方法会发生动态绑定,调用的是子类的重写方法,那么我将子类的代码修改成下面的代码

public class Dog extends Animal{
    int num=1;
   public void fun() {
         System.out.println(num);
    }
}

其实例化后结果会是什么?1吗?

但结果是0,为什么?

这就考察到了代码块的顺序,我们知道代码块的顺序是先执行父类和子类静态代码块顺序,在父类的实例和构造在子类的实例和构造。 

  • 26
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值