目录

一、多态的概念

二、向上转型

三、向下转型

四、抽象类


 

一、多态的概念

多态:意味着允许不同类的对象对同一消息做出不同的响应

多态的分类

  • 编译时多态(设计师多态)
  • 方法重载
  • 运行时多态
  • Java运行时系统根据调用该方法的实例的类型来决定选择调用那个方法则被称为运行时多态
  • 必要条件
  • 满足继承关系
  • 父类引用指向子类对象

二、向上转型

  • 向上转型、隐式转型、自动转型
  • 父类引用指向子类实例,
  • 可以调用子类重写父类的方法以及父类派生的方法
  • 子类特有的方法不能直接去调用
  • 小类型转为大类型

三、向下转型

  • 向下转型又称为强转
  • 子类引用指向父类对象,此处必须进行强转,可以调用子类特有的方法了
  • 必须满足转换条件才能转换
  • A instanceof B语句表示左边对象引用类型是否可满足右边类型实例特征
  • 向下转型一般是为了重新获得因为向上转型而丢失的子类特性而存在的,因此通常在向下转型前需要先进行向上转型,向下转型也会结合instanceof一起应用

这边我们举个例子吧

Cat类和Dog类都是Animal类的子类。

Animal

  • 构造方法,私有属性name和month,以及他们的get/set方法,公有eat方法

Cat类

  • 构造方法,特有的私有属性weight,以及他的get/set方法,重写的eat方法,特有的公有run方法

Dog类

  • 构造方法,特有的私有属性sex,以及他的get/set方法,重写的eat方法,特有的公有sleep方法
public static void main(String[] args){
        Animal one = new Animal();
        /***
         向上转型、隐式转型、自动转型
         父类引用指向子类实例,
         可以调用子类重写父类的方法以及父类派生的方法
         子类特有的方法不能直接去调用
         注意:父类中的静态方法无法被子类重写,所以向上转型之后,只能调用到父类原有的静态方法
         小类型转为大类型
         ***/
        Animal two = new Cat();
        Animal three = new Dog();

        one.eat();
        two.eat();
        two.getMonth();
//        two.run(); // 无法直接调用子类特有的方法
        three.eat();

        System.out.println("======================");
        /***
         * 向下转型、强制类型转换
         * 子类引用指向父类对象,此处必须进行强转,可以调用子类特有的方法了
         * 必须满足转换条件才能转换
         * A instanceof B语句表示左边对象引用类型是否可满足右边类型实例特征
         */
        System.out.println(two);
        System.out.println(one);
        if(two instanceof Cat) {
            Cat tempCat = (Cat)two;
            ((Cat)two).eat();
            tempCat.eat();
            tempCat.run();
            tempCat.getMonth();
            System.out.println(tempCat);
            System.out.println("two可以转换成Cat类型");
        }

//        Dog tempDog = (Dog)one;
        System.out.println(two instanceof Dog);
        System.out.println(three instanceof Dog);

    }
}

输出:我们可以看出two是指向Cat类型的对象的,尽管two的类型是animal类型,不过受限于two的类型,它只可以调用Animal派生的方法以及子类重写的方法,无法调用子类特有的方法。

two指向的其实是Cat类型的对象,因此将其强转回Cat不会有任何问题,强转之后就可以调用子类特有的方法了,当然依旧可以调用Animal派生的方法以及子类重写的方法。

不过我们也可以看到two是Animal类型的对象,指向的是Cat类型的对象,故无法强转为Dog类型。

Animal的eat
Cat的eat
Dog的eat
======================
com.imooc.animal.Cat@6e0be858
com.imooc.animal.Animal@61bbe9ba
Cat的eat
小猫快乐的奔跑
com.imooc.animal.Cat@6e0be858
two可以转换成Cat类型
false
true

这边我们注意一下static关键字,,给三个类均添加静态的say方法public static void say(),我们看看效果。

public static void main(String[] args) {
    Animal one = new Cat();
    one.say();
    Cat two = new Cat();
    two.say();
    ((Cat) one).say();
}

输出,解释一下,Cat的say和Animal的say不构成重写,只是在Cat的say内Animal的say被隐藏了,Cat的say算Cat的特有方法,故one只能调用父类自己派生的say方法。若想调用Cat的say,可以先强转回Cat类型。

Animal的say
Cat的say
Cat的say

四、抽象类

作用

  • 在面向对象的概念中,所以的对象都是通过类来描述的,但并不是所有的类都是用来描述对象的。当一个类中没有包含足够的信息以描绘一个具体的对象时,这样的类就是抽象类。

定义抽象类的意义在于:

  • 为其子类提供一个公共的类型(父类引用指向子类对象)
  • 封装子类中的重复内容(成员变量和方法)
  • 将父类设计成抽象类后,既可借由父子继承关系限制子类的设计随意性,在一定程度上避免了无意义父类的实例化。

抽象类的特点:

  • 抽象类不允许直接实例化,换句话说抽象类不能通过new关键字创建对象,它只能作为其他类的父类。但可以通过向上转型,指向子类实例。
  • 当类中存在抽象方法,则必须声明为抽象类。
  • 抽象类中可以没有抽象方法。
  • 子类继承抽象类后,必须重写所有抽象方法,否则也只能是抽象类;不同的子类对父类的抽象方法可以有不同的实现
  • abstract方法不能用static和private修饰;对于类,不能同时使用final和private修饰。因为final关键字使得类不能被继承,而abstract修饰的类如果不能被继承将没有任何意义。两者放在一起,也会发生编译异常。 
  • 抽象方法在子类实现时访问权限必须大于等于父类方法(这一点很好理解,重写的要求)