day11_多态丶抽象类

多态

什么是多态?

  • 同一个对象,在不同时刻表现出来的不同形态

前提【重点】

  • 继承或者实现【二选一】
  • 方法的重写【意义体现:不重写,无意义】
  • 父类引用指向子类对象【格式体现】

多态的体现

注意:

Java引用变量有两个类型:编译时类型和运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。简称:编译时,看左边;运行时,看右边。

多态中的成员访问特点

  • 不管是成员变量还是成员方法,编译的时候,父类中必须存在,否则编译都不会通过,会报错。

总结:

  • 当使用多态方式调用成员变量时,首先检查父类中是否有该变量,如果没有,则编译错误;如果有,执行的是父类中的变量
  • 当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后方法

为什么成员方法和成员变量不同?

  • 因为成员方法有重写,而成员变量没有
  • 成员变量:不具备多态性,只看引用变量所声明的类

代码演示

定义父类

public class Animal {
    public int age = 40;

    public void eat() {
        System.out.println("动物吃东西");
    }
}

定义子类

public class Cat extends Animal {
    public int age = 20;
    public int weight = 10;

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    public void playGame() {
        System.out.println("猫捉迷藏");
    }
}

定义测试类

public class AnimalDemo {
    public static void main(String[] args) {
        //有父类引用指向子类对象
        Animal a = new Cat();
        // 当使用多态方式调用成员变量时,首先检查父类中是否有该变量,如果没有,则编译错误;如果有,执行的是父类中的变量
        System.out.println(a.age);//40
        //当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后方法
        a.eat();//猫吃鱼

    }
}

多态的好处

  • 实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利。

多态的弊端

  • 一个引用类型变量如果声明为父类的类型,但实际引用的是子类 对象,那么该变量就不能再访问子类中添加的属性和方法

如何解决多态的弊端

我们可以使用引用类型转换来解决多态的弊端,多态的转型分为向上转型与向下转型两种

向上转型

  • 向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。 当父类引用指向一个子类对象时,便是向上转型。

使用格式:

向下转型

向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。

使用格式:

转型的异常

转型的过程中,一不小心就会遇到这样的问题ClassCastException ,类型转换异常。为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:

所以,转换前,我们最好先做一个判断,代码如下:

public class AnimalDemo {
    public static void main(String[] args) {
        // 向上转型 
        Animal a = new Cat();
        a.eat();
        // 调用的是 Cat 的 eat 
        // 向下转型 
        if (a instanceof Cat) {
            Cat c = (Cat) a;
            c.catchMouse();
            // 调用的是 Cat 的 catchMouse 
        } else if (a instanceof Dog) {
            Dog d = (Dog) a;
            d.watchHouse(); // 调用的是 Dog 的 watchHouse 
        }
    }
}

总结一下类型转换

                          

抽象类

什么是抽象类

父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有 意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法Java语法规定,包含抽象方法的类就是抽象类

抽象类与抽象方法

  • abstract关键字来修饰一个类,这个类叫做抽象类
  • abstract来修饰一个方法,该方法叫做抽象方法。 抽象方法:只有方法的声明,没有方法的实现。以分号结束: 比如:public abstract void talk();

抽象方法

使用 abstract 关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。

定义格式:

抽象类

如果一个类包含抽象方法,那么该类必须是抽象类。

定义格式:

抽象类的成员特点

  • 成员变量:既可以是变量也可以是常量
  • 构造方法:可以有空参构造也可以有参构造
  • 成员方法:可以有抽象方法也可以有普通方法

抽象的使用

继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父 类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。

代码演示

定义抽象类

/*
抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束。
抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可。

如何使用抽象类和抽象方法:
1. 不能直接创建new抽象类对象。
2. 必须用一个子类来继承抽象父类。
3. 子类必须覆盖重写抽象父类当中所有的抽象方法。
覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。
4. 创建子类对象进行使用。
 */
public abstract class Animal {

    // 这是一个抽象方法,代表吃东西,但是具体吃什么(大括号的内容)不确定。
    public abstract void eat();

    // 这是普通的成员方法
    public void normalMethod() {
    }

}

定义实现类

package cn.itcast.day09.demo11;

public class Cat extends Animal {

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

}

此时的方法重写,是子类对父类抽象方法的完成实现,我们将这种方法重写的操作,也叫做实现方法

定义测试类

package cn.itcast.day09.demo11;

public class DemoMain {

    public static void main(String[] args) {
    //  Animal animal = new Animal(); // 错误写法!不能直接创建抽象类对象
        Cat cat = new Cat();
        cat.eat();
    }

}

注意事项

1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。

  • 理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。

2. 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。

  • 理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
3. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
  • 理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设 计。

4. 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。

  • 理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。 ​​​​​​​
展开阅读全文
©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读