Java多态实例详解三步走(二)【抽象类多态】

概述:在Java中,一个没有方法的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。

多态分为三种:

  • 具体类多态(几乎没有):
    class Fu { }
    class Zi extends Fu { }

    Fu f = new Zi();
    请看 Java多态实例详解三步走(一)【具体类多态】

  • 抽象类多态(常用):
    abstract class Fu { }
    class Zi extends Fu { }

    Fu f = new Zi();

  • 接口类多态(最常用):
    interface class Fu { }
    class Zi implements Fu { }

    Fu f = new Zi();
    请看 Java多态实例详解三步走(三)【接口多态】

    多态中必须对方法进行重写,其实是针对于抽象类来说的。因为父类中虽然是对某一种事或物共同的特点,但是,比如说动物。所有的动物都要吃东西,而大象是用鼻子卷着吃,猴子是用手拿着吃,所以定义的子类就要重写方法,既然要重写那为什么不把父类中的方法抽象呢。

一、抽象类的特点:
1、 抽象类和抽象方法必须用abstract关键字修饰。
2、 抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类。
3、 抽象类不能实例化。

  • 因为它不是具体的
  • 抽象类有构造方法,但是不能实例化
  • 构造方法的作用是,用于子类访问父类数据的初始化

4、抽象的子类

  • 如果不想重写抽象方法,该子类是一个抽象类。
  • 重写所有的抽象方法,这个时候子类是一个具体的类。

抽象类的实例化其实是靠具体的子类实现的。是多态的方式。
A a = new B();

代码1:


public class Main {
    public static void main(String[] args) {
        //抽象类无法创建对象,也就是无法实例化
        //AA a = new AA();//这里会报错  Cannot instantiate the type AA

        //通过多态调用
        A a = new C();
        a.eat();//输出  吃饭了
    }
}

abstract class AA {}

abstract class A {
    //下面这种叫 空方法体,不是抽象方法,所以会报错
    //public abstract void eat() {}

    //正确格式
    public abstract void eat();//如果将这行注释,同样不会报错。因为抽象类不一定有抽象方法
}

//子类是抽象类
abstract class B extends A {}

//子类是具体类,重写全部抽象方法
class C extends A {
    public void eat() {
        System.out.println("吃饭了");
    }
}

二、抽象类的成员特点:
1、成员变量:即可以是变量,也可以是常量。
2、构造方法:有。

  • 用于子类访问父类数据的初始化

3、成员方法:既可以是抽象的,也可以是非抽象的。

  • 抽象类的成员方法特性:
    1、抽象方法:强制要求子类做的事情。
    2、非抽象方法:子类继承的事情,提高代码复用性。

代码2:


public class Main {
    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.flag);//输出 19
        System.out.println(a.logo);//输出 77
        a.show();//输出  重写抽象方法
        a.show2();//输出  非抽象方法
    }
}

abstract class A {
    int flag = 19;
    final int logo = 77;

    public A() {}

    public A(String args) {}

    public abstract void show();

    public void show2() {
        System.out.println("非抽象方法");
    }
}

class B extends A {
    public void show() {
        System.out.println("重写抽象方法");
    }
}

抽象类中的小问题:

  • abstract不能和一些关键字共存
  • private 发生冲突
  • final  发生冲突
  • static  无意义
abstract class Fu{
    //私有的不能被重写,而多态中要求被重写
    //private abstract void show();

    //最终的不能被修改,而多态中要求被重写
    //final abstract void show2();

    //这里会跟上边两个一样报非法修饰符组合,同时也是无意义的
    //static abstract void show3();
    //因为,该方法是静态的,我就可以通过类名进行调用 Fu.show3();
    //但是因为该方法是抽象方法,没有方法体,所以无意义
}

class Zi extends Fu {
    /*public void show(){
        System.out.println(123);
    }

    public void show2() {
        System.out.println(528);
    }

    public void show3() {
        System.out.println(520);
    }
    */
}

最后用一个代码完整的写出多态
代码3:


public class Main {
    public static void main(String[] args) {
        Animal a = new Dog();
        a.setName("小黄狗");
        a.setAge(2);
        System.out.println(a.getName());
        System.out.println(a.getAge());
        a.eat();
        System.out.println("------------------");
        a = new Cat();
        a.setName("小花猫");
        a.setAge(6);
        System.out.println(a.getName());
        System.out.println(a.getAge());
        a.eat();
        //如果非要访问子类中特有的成员变量或者方法,那就建一个具体的对象
        Dog t = new Dog();
        t.flag = 90;
        System.out.println(t.flag);
    }
}

abstract class Animal {
private int age;
private String name;

public Animal() {}

public Animal(int age, String name) {
this.age = age;
this.name = name;
}

public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

abstract void eat();

}

class Dog extends Animal {

public Dog() {}
public Dog(int age, String name) {
super(age, name);
}

public void eat() {
System.out.println(“狗吃东西”);
}
}

class Cat extends Animal {
public Cat() {}
public Cat(int age, String name) {
super(age, name);
}

public void eat() {
System.out.println(“猫吃东西”);
}
}