代码改变世界

开源搜索框架Lucene学习之分词器(3)——通过分词器源码学习抽象方法与虚方法的区别

2012-01-04 17:37  左眼微笑右眼泪  阅读(491)  评论(0编辑  收藏  举报

   在我研读分词器源码的过程中,又碰到了以前还未完全弄明白的抽象方法与虚方法。下面我将结合源码里面的内容,重新来学习一些抽象方法与虚方法的区别。

   下面是分词器模块中的一部分类的关系图。

image

TokenStream类是所有类的父类。TokenStream类里面有两个方法,看下面的代码:

abstract public class TokenStream
{
    ///<summary>
    ///返回语汇单元流中的下一个词元,或者是空,也就是结束,返回EOS
    ///Returns the next token in the stream, or null at EOS. 
    ///</summary>
    abstract public Token Next();
 
    ///<summary>
    ///释放语汇单元流所使用的资源
    ///</summary>
    public virtual void Close()
    {
    }
}

Next是一个抽象方法,Close是一个虚方法。通过上面的代码,我们就可以看出一些区别:

抽象方法:

1.以abstract修饰,abstract在Public的前面。没有方法体,在小括号后面直接跟一分号就结束,没有大括号。

2.有抽象方法的类一定是抽象类,我们可以看到TokenStream类是一个抽象的类。但抽象类中可以有非抽象的方法,比如Close就是非抽象的方法。

虚方法:

1.以virtual修饰,virtual在Public的后面。有方法体,在小括号的后面跟着一对大括号。此大括号里可以有方法的实现,也可以没有,此处为没有实现。

我们再来看看TokenStream类的一个子类TokenFilter,它的代码如下:

abstract public class TokenFilter : TokenStream
{
    ///<summary>
    ///需要传过来的处理的TokenStream
    ///The source of tokens for this filter. 
    ///</summary>
    protected TokenStream input;
 
    ///<summary> Close the input TokenStream. </summary>
    public override void Close()
    {
        input.Close();
    }

     可以看到此类实现了虚方法Close,但是却找不到抽象方法Next的踪迹。这是为什么呢,不是说子类一定要实现抽象方法,不一定要实现虚方法的吗,难道有错?。我们再来看看TokenFilter这个类,需要注意,它前面有一个abstract来修饰,这说明它是一个抽象类。所以一切就明白了。确切的来说:

     非抽象的子类一定要实现父类的抽象方法。也就是子类一定要实现父类的抽象方法,如果没有实现,那么这个子类一定也是个抽象类,那么父类的抽象方法就由这个子类的非抽象子类去实现。

     子类不一定要实现父类的虚方法,不管这个类是不是抽象类。

      我们再来看看TokenFilter的子类LowerCaseFilter类,它的代码如下:

public class LowerCaseFilter : TokenFilter
{
    /// <summary>
    /// Initializes a new instance of the LowerCaseFilter class.
    /// </summary>
    /// <param name="ts">Token stream to read from.</param>
    public LowerCaseFilter(TokenStream ts)
    {
        input = ts;
    }
 
    /// <summary>
    /// Returns the next token from the stream.
    /// </summary>
    /// <returns>The next token or null if EOS.</returns>
    public override Token Next()
    {
        Token t = input.Next();
 
        if (t == null)
            return null;
 
        t.TermText = t.TermText.ToLower();
 
        return t;
    }
}
可以看到这个类不是抽象类,所以我们看到它实现了TokenStream中的抽象方法Next,但是它并没有实现虚方法Close。还有一点需要注意的是不管是抽象方法还是虚方法,子类在实现这个方法的时候,需要在前面加上关键字override。

因为抽象方法是强制要求非抽象子类必须实现,所以不能用Sealed来修饰抽象方法,因为Sealed表示这个方法不能被继承,而抽象方法又必须需要子类来实现。

     最后来总结一下两者的区别:

     1.抽象方法与虚方法的定义方式不同,抽象方法是用abstract来修饰,虚方法是用virtual修饰。抽象方法是小括号后面加一个分号,而虚方法是小括号后面还有大括号,大括号里面可以有方法的实现内容,也可以没有。

     2.有抽象方法的类一定是抽象类,抽象类中的方法不一定非要是抽象方法,也可以有其他的非抽象方法。而普通类中也可以有虚方法求。

     3.非抽象的子类一定要实现父类中的抽象方法,而对于虚方法,子类可以实现,也可以不实现。

     4.抽象方法不能与Sealed关键字一起使用。

     5.子类实现抽象方法或虚方法,需要在前面加上override关键字。