抽象类

每一个技术的出现, 都是为了解决某一种问题的.

抽象类的出现, 就是为了让子类强制重写父类中的某一个方法.

父类的抽象方法在子类中必须重写, 否则子类代码直接报错.

抽象方法所在的类就叫做抽象类.

抽象类和抽象方法主要学习:

  1. 抽象类的定义格式.

  2. 抽象方法的定义格式.

  3. 子类继承抽象类之后, 如何重写抽象方法.

  4. 抽象类在实际开发中的意义所在.

将多个子类中的共的行为 (方法) 抽取到父类之后, 由于每一个子类的执行的内容是不一样的, 所以父类中不能确定具体的方法体, 则该方法可以被定义为抽象方法.

如果一个类里面存在抽象方法, 不管有多少个, 那么这个类就必须被定义为抽象类.

抽象方法是不写方法体的, 直接用分号结束, 连花括号都没有. 抽象方法的定义格式为: public abstract 返回值类型 方法名 (参数列表);

抽象类的定义格式为: public abstract class 类名 { 类体 }

程序示例:

public abstract class Person {
    public abstract void work();
}

抽象类不能实例化 (实例化即创建对象). 如果可以实例化, 则抽象类的对象可以调用抽象类的方法, 包括抽象方法, 而抽象方法没有方法体, 那么调用什么呢?由此就产生了矛盾, 因此规定抽象类不能实例化.

抽象类中不一定有抽象方法, 但是有抽象方法的类一定是抽象类.

抽象类可以有构造方法. 既然抽象类不能实例化, 那么抽象类的构造方法有何作用? 作用: 当其子类创建对象时, 可以给子类对象赋值. 子类的构造方法用 super 调用父类的构造方法. 抽象类的构造方法是给可以实例化的子类通过 super() 来使用的.

抽象类的子类要么重写抽象类的所有抽象方法, 要么子类本身也是一个抽象类. 如果子类还是抽象类, 那么这个子类还是不能实例化, 如果想创建对象, 那就要再定义 "孙子类", 且一定不是抽象类, 那么这个 "孙子类" 还是要重写全部的抽象方法. 所以一般都是采用第一种方法, 即在子类中重写全部的抽象方法.

也就是说, 一般情况下, 抽象类的子类不是抽象类.

程序示例:

public abstract class Person {  // 是抽象类但是没有抽象方法
    // public abstract void work();
    public void sleep() {
    }
}
public class Person {  // 有抽象方法但不是抽象类, 则报错
    public abstract void work();

    public void sleep() {
    }
}
public abstract class Person {  // 带有构造方法的抽象类
    String name;
    int age;

    public Person() {
    }

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

    public abstract void work();

    public void sleep() {
    }
}

练习:
编写带有抽象类的标准 Javabean 类
青蛙 Frog: 属性: 名字, 年龄 行为: 吃虫子, 喝水
狗 Dog: 属性: 名字, 年龄 行为: 吃骨头, 喝水
山羊 Sheep: 属性: 名字, 年龄 行为: 吃草, 喝水

画出示意图:


图 1

Javabean 类:

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

    public Animal() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public void drink() {
        System.out.println(getName() + "在喝水. ");
    }

    public abstract void eat();
}
public class Dog extends Animal {
    public Dog() {
    }

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

    @Override
    public void eat() {
        System.out.println("狗在吃骨头. ");
    }
}
public class Frog extends Animal {

    public Frog() {
    }

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

    @Override
    public void eat() {
        System.out.println("青蛙在吃虫子. ");
    }
}
public class Sheep extends Animal {
    public Sheep() {
    }

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

    @Override
    public void eat() {
        System.out.println("羊在吃草. ");
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        Frog f = new Frog("小绿", 1);
        System.out.println(f.getName() + ", " + f.getAge());
        f.eat();
        f.drink();
    }
}

执行结果:

小绿, 1
青蛙在吃虫子. 
小绿在喝水. 

在父类中定义抽象类, 在子类中又重写, 看起来是很麻烦, 因为在父类中多写了一个类, 但是这样做是有意义的, 因为假如有多个人去调用这个父类写了多个子类, 如果没有这个抽象类限制了子类中的这个类的书写形式, 那么不同的人所写的子类中的这个方法可能差别很大, 另外的人去调用时, 不知道该如何调用, 如果在父类中写了这个抽象类, 就相当于限定了这个类的形式, 调用时如果不知道如何调用, 只需要去父类中看看就知道了. 所以, 父类中定义抽象类有统一形式的意义.

抽象的子类的父类不一定是抽象的, 可能子类特有的方法是抽象方法.

posted @ 2024-09-10 22:16  有空  阅读(23)  评论(0)    收藏  举报