20、抽象类与模板设计模式

抽象类

基本概念

1、抽象类是含有抽象方法的类。抽象方法没有方法体,必须用abstract定义。

abstract class A { // 抽象类
    public void fun(){方法体;} // 普通方法
    public abstract void print(); // 抽象方法
}

public class Demo {
    public static void main(String[] args) {
        A a = new A(); // 报错,A是抽象类,无法实例化
    }
}

结果显示,无法直接实例化抽象类对象.普通类的对象实例化后,该对象可以调用类中的属性和方法.而抽象类中存在抽象方法,抽象方法没有方法体无法调用,因此无法产生实例化对象.
2、抽象类使用原则:

(1)抽象类必须有子类;
(2)抽象类的子类(非抽象类时)必须覆写抽象类中所有的抽象方法(强制子类进行方法覆写)
(3)抽象类对象的实例化依靠子类完成,采用向上转型方式。

范例:使用抽象类

abstract class A { // 抽象类
    public void fun() { // 普通方法
        System.out.println("普通方法");
    }

    public abstract void print(); // 抽象方法
}

class B extends A {
    // 强制要求对抽象方法进行覆写,否则会报错
    public void print() {
        System.out.println("覆写后的抽象方法");
    }
}

public class Demo {
    public static void main(String[] args) {
        A a = new B(); // 向上转型
        a.fun();
        a.print();
    }
}

由上述代码,可知:

(1)抽象类的子类明确要求方法覆写,而普通类没有;
(2)抽象类只比普通类多了抽象方法,其他部分相同;
(3)抽象类对象必须经过向上转型才能实例化;
(4)虽然子类可以继承任何类,但开发中,普通类最好继承抽象类。

使用限制

1、抽象类由于存在属性,因此会有构造方法来初始化属性。子类对象实例化时依然先执行父类构造方法,再调用子类构造方法。
2、抽象类不能使用final定义,因为抽象类必须有子类。
3、抽象外部类不允许使用static定义,而抽象内部类可以使用static声明。使用static定义的抽象内部类相当于抽象外部类,继承时使用外部类.内部类的形式表示类名。

abstract class A { // 抽象类
    static abstract class B {
        public abstract void print();
    }
}

class X extends A.B {
    public void print() {
        System.out.println("*****");
    }
}

public class Demo {
    public static void main(String[] args) {
        A.B ab = new X(); // 向上转型
        ab.print();
    }
}

4、static定义的方法可以没有实例化对象的情况下直接调用,即使是抽象类中的static方法。

abstract class A { // 抽象类
    public static void print() {
        System.out.println("static方法");
    }
}

public class Demo {
    public static void main(String[] args) {
        A.print(); // static方法
        A a = new A() ; // 报错
    }
}

5、有时抽象类只需要一个特定的子类操作,因此可以将该子类定义为该抽象类的内部类。

abstract class A { // 抽象类
    public abstract void print();

    private static class B extends A { // 内部抽象类子类
        public void print() {
            System.out.println("Hello");
        }
    }

    public static A getInstance() { // 获取B的实例化对象
        return new B();
    }
}

public class Demo {
    public static void main(String[] args) {
        // 客户端得到抽象类对象时,B对其不可见
        A a = A.getInstance();
        a.print();
    }
}

上述设计在系统类库中较为常见,目的是:为用户隐藏不需要知道的子类。
6、观察下述代码:

abstract class A { // 抽象类
    // 1. 先调用父类构造
    public A() {
        this.print();
    }

    public abstract void print();
}

class B extends A {
    private int num = 100;
    // 3.调用子类构造,并初始化num = 30.运行结束,未输出初始化后的num
    public B(int num) {
        this.num = num;
    }
    // 2. 父类构造调用子类的print,此时num = 0,打印输出。
    public void print() {
        System.out.println("num = " + num);
    }
}

public class Demo {
    public static void main(String[] args) {
        new B(30); // 4. 结果为0
    }
}

在构造方法执行完之前,属性的内容均为其对应的数据类型的默认值。子类在执行构造方法前必先执行父类的构造方法,因为此时子类构造方法还没执行,就调用print()输出了num的值,所以num为0.

模板设计模式

要求:设计三个类,通过类描述如下行为:
(1)机器人:充电、工作;
(2)人:吃饭、工作、睡觉;
(3)猪:吃饭、睡觉
思路:定义一个抽象类,具有吃饭、睡觉、工作的抽象方法。根据子类的不同,具体实现抽象方法。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Oy51FpX-1570848167779)(/18-2.png “思路图”)]

abstract class Action {
    public static final int EAT = 1;
    public static final int SLEEP = 5;
    public static final int WORK = 7;

    public void command(int flag) {
        switch (flag) {
            case EAT:
                this.eat();
                break;
            case SLEEP:
                this.sleep();
                break;
            case WORK:
                this.work();
                break;
            case EAT + WORK:
                this.eat();
                this.work();
                break;
        }
    }
    // 不确定方法中的具体行为,定义为抽象类
    public abstract void eat();

    public abstract void sleep();

    public abstract void work();
}

定义子类

class Robot extends Action {
    public void eat() {
        System.out.println("机器人正在补充能量");
    }

    public void sleep() {
    }

    public void work() {
        System.out.println("机器人正在工作");
    }
}

class Human extends Action {
    public void eat() {
        System.out.println("人正在吃饭");
    }

    public void sleep() {
        System.out.println("人正在睡觉");
    }

    public void work() {
        System.out.println("人正在工作");
    }
}

class Pig extends Action {
    public void eat() {
        System.out.println("猪正在吃饭");
    }

    public void sleep() {
        System.out.println("猪正在睡觉");
    }

    public void work() {
    }
}

范例:测试程序

public class Demo {
    public static void main(String[] args) {
        fun(new Robot());
        fun(new Human());
        fun(new Pig());
    }

    public static void fun(Action act) {
        act.command(Action.EAT);
        act.command(Action.SLEEP);
        act.command(Action.WORK);
    }
}

结果显示:子类要实现操作,必须按照Action类的标准。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值