0.7、Spring源码学习 ——从接口的抽象方法和抽象类的抽象方法说起

文章目录

        • 前言
        • 点睛之笔:接口的抽象方法和抽象类的抽象方法的应用差别?
        • 举个例子
          • UML 关系图
          • 关门,放代码
            • 抽象父类 Top
            • 子类 Bottom
            • 测试方法 和 结果
        • 最佳实践
        • JDK 源码中的 java.io.InputStream
        • 设计模式的模版方法模式

前言

体能状态先于精神状态,习惯先于决心,聚焦先于喜好。

点睛之笔:接口的抽象方法和抽象类的抽象方法的应用差别?

本文主要就是围绕这一点来说的
差异所在:相较于接口的抽象方法,抽象类的抽象方法可以在抽象类的内部被其他普通方法直接调用,注意,此时的抽象方法并没有具体的实现,需要子类继承抽象类后重写这个抽象方法完成具体逻辑
尽管这在代码中看起来有些诡异,但是这是一个非常重要并且实用的特性

举个例子

UML 关系图

抽象类 Top,包含一个普通方法 printBotomName,一个抽象方法 getName
printBotomName 内部 有直接调用 getName 的逻辑,具体看代码部分

0.7、Spring源码学习 ——从接口的抽象方法和抽象类的抽象方法说起_第1张图片

关门,放代码
抽象父类 Top

父类,抽象类,内部包含一个普通方法和一个抽象方法,普通方法内部调用了抽象方法

package com.bestcxx.stu.jms.del;

/**
 * 定义一个抽象类
 * 抽象类内部普通方法调用本类的抽象方法
 */
public abstract class Top {
    /**
     * 内部调用本抽象类的抽象方法
     * 抽象方法的实现由子类来完成
     */
    public final void printBottomName(){
        String name=getName();
        System.out.println("name:"+name);
    }

    /**一个抽象方法*/
    abstract String getName();
}

子类 Bottom

子类,继承了抽象类,并重写抽象方法

package com.bestcxx.stu.jms.del;

public class Bottom extends Top {
    @Override
    String getName() {
        return "来自子类的名字-抽象父类可以直接调用自己的抽象方法";
    }
}

测试方法 和 结果

抽象类自身无法被自己实例化,必须借助于一个具体的子类-非抽象的子类

package com.bestcxx.stu.jms.del;

import org.junit.Test;

public class TopTest {
    @Test
    public void testPrintBottomName(){
        Top t=new Bottom();
        t.printBottomName();
    }
}

输出结果

name:来自子类的名字-抽象父类可以直接调用自己的抽象方法

最佳实践

在抽象类中调用一个抽象方法,然后依靠子类完成具体的功能,这在你不了解情况的时候代码看起来会有些诡异,尤其在子类众多之时,你无法直接跳转到具体的子类的重写方法中,因为IDE也无法通过静态的代码得知这些。
尽管如此,抽象类的抽象方法所体现出的这种特性有着十分广泛的应用,当你面临多种情况,并且多重情况有很大一部分逻辑是重复的时候,可以将重复逻辑写到父类中的一个普通方法中,对于多种情况的特殊情况,则可以提供一个抽象方法,然后由子类来完成具体的逻辑。
至于跟踪代码这件事,你应该学会熟练的使用 debug ,在代码测试的时候进入到具体的子类中——相信我,在Spring 源码中这招很管用
再一个,抽象类中的抽闲方法如果确定要被抽象类本身调用,那么抽象类的普通方法最好使用final修饰,避免子类不小心进行了修改,当然这要依情况而定。

JDK 源码中的 java.io.InputStream

抽象类

public abstract class InputStream implements Closeable {

抽象方法-注释要求子类必须实现该方法

public abstract int read() throws IOException;

一个普通方法 调用了 抽象方法 read()

public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }

设计模式的模版方法模式

本文论述的情况其实就是设计模式中的模版方法模式
你可以认为 java.io.InputStream 体现了模版方法模式,尽管一般来说,Java IO常常和装饰器模式联系在一起描述.

你可能感兴趣的:(Spring,源码,Spring,源码学习)