有些情况下,你希望定义一个超类,该超类定义了一种给定结构的抽象但是不提供任何完整的方法实现。也就是说,有时你希望创建一个只定义一个被它的所有子类共享的通用形式,由每个子类自己去填写细节。

这样的类决定了子类所必须实现的方法的本性。这类情形下一种可能发生的情况是超类不能创建一个方法的有意义的实现。前面的例子中用到的类Figure就属于这种情况。area( )的定义仅是一个占位符。它不会计算和显示任何类型对象的面积。

当创建自己的类库时你会看到,超类中的方法没有实际意义并不罕见。你有两种方法可以处理这种情况。第一种,如前面的例子所示,仅仅是报告一个出错消息。

尽管这种方式在某些场合是有用的——例如调试——但是它不是很适用的。你还有一种方法就是通过子类重载该方法以使它对子类有意义。

考虑Triangle类,如果不定义area( )它是毫无意义的。这种情况下,你希望有方法确保子类真正重载了所有必须的方法。Java对于这个问题的解决是用抽象方法。

你可以通过指定abstract类型修饰符由子类重载某些方法。这些方法有时被作为子类责任引用,因为它们没有在超类中指定的实现。这样子类必须重载它们——它们不能简单地使用超类中定义的版本。声明一个抽象方法,用下面的通用形式:

abstract type name(parameter-list);

正如你所看到的,不存在方法体。任何含有一个或多个抽象方法的类都必须声明成抽象类。声明一个抽象类,只需在类声明开始时在关键字class前使用关键字abstract。抽象类没有对象。

也就是说,一个抽象类不能通过new操作符直接实例化。这样的对象是无用的,因为抽象类是不完全定义的。而且,你不能定义抽象构造函数或抽象静态方法。所有抽象类的子类都必须执行超类中的所有抽象方法或者是它自己也声明成abstract。

下面是具有一个抽象方法类的简单例题。该类后面是一个执行抽象方法的类:

// A Simple demonstration of abstract.
abstract class A { abstract void callme(); // concrete methods are still allowed in abstract classes void callmetoo() { System.out.println("This is a concrete method."); }
}
class B extends A { void callme() { System.out.println("B's implementation of callme."); }
}
class AbstractDemo { public static void main(String args[]) { B b = new B(); b.callme(); b.callmetoo(); }
}

注意程序中声明A的对象。刚刚讲过,实例化一个抽象类是不可能的。另外一点要注意:类A实现一个具体的方法callmetoo( )。这是完全可接受的,抽象类可以包括它们合适的很多实现。

因为Java的运行时多态是通过使用超类引用实现的,所以尽管抽象类不能用来实例化,它们可以用来创建对象引用。这样,创建一个抽象类的引用是可行的,这样它可以用来指向一个子类对象。在下面的程序中你将会看到这种特性的运用。

运用抽象类,你可以改善前面所显示的Figure类。因为对于一个未定义的二维图形,面积的概念是没有意义的,下面的程序在Figure内将area( )定义成抽象方法。这样当然意味着从Figure派生的所有类都必须重载area( )方法。

// Using abstract methods and classes.
abstract class Figure { double dim1; double dim2; Figure(double a, double b) { dim1 = a; dim2 = b; } // area is now an abstract method abstract double area();
}
class Rectangle extends Figure { Rectangle(double a, double b) { super(a, b); } // override area for rectangle double area() { System.out.println("Inside Area for Rectangle."); return dim1 * dim2; }
}
class Triangle extends Figure { Triangle(double a, double b) { super(a, b); } // override area for right triangle double area() { System.out.println("Inside Area for Triangle."); return dim1 * dim2 / 2; }
}
class AbstractAreas { public static void main(String args[]) { // Figure f = new Figure(10, 10); // illegal now Rectangle r = new Rectangle(9, 5); Triangle t = new Triangle(10, 8); Figure figref; // this is OK, no object is created figref = r; System.out.println("Area is " + figref.area()); figref = t; System.out.println("Area is " + figref.area()); }
}

Main()内的注释暗示,定义Figure类型的对象不再是可能的了,因为现在它是抽象类。而且,所有Figure的子类都必须重载area( )方法。为证明这点,试着创建不重载area( )的子类。你会收到一个编译时错误。

尽管不可能创建一个Figure类型的对象,你可以创建一个Figure类型的引用变量。变量figref声明成Figure的一个引用,意思是说它可以用来引用任何从Figure派生的对象。刚才解释过的,通过超类引用变量重载方法在运行时解决。

开课吧Java课堂:什么是抽象类?如何使用抽象类?相关推荐

  1. 开课吧Java课堂:什么是流?如何运用字节流和字符流?

    Java程序通过流来完成输入/输出.流是生产或消费信息的抽象.流通过Java的输入/输出系统与物理设备链接.尽管与它们链接的物理设备不尽相同,所有流的行为具有同样的方式.这样,相同的输入/输出类和方法 ...

  2. 开课吧Java课堂:如何通过接口引用实现接口?

    你可以把变量定义成使用接口的对象引用而不是类的类型.任何实现了所声明接口的类的实例都可以被这样的一个变量引用.当你通过这些引用调用方法时,在实际引用接口的实例的基础上,方法被正确调用.这是接口的最显著 ...

  3. 开课吧Java课堂之如何使用FilenameFilter

    你总是希望能够限制由list( )方法返回的文件数目,使它仅返回那些与一定的文件名方式或者过滤(filter)相匹配的文件.为达到这样的目的,必须使用list( )的第二种形式: String[ ] ...

  4. 开课吧Java课堂:如何使用比较函数?

    下面是一个说明定制的比较函数能力的例子.该例子实现compare( )方法以便它按正常顺序的逆向进行操作.因此,它使得一个树集合按逆向的顺序进行存储. // Use a custom comparat ...

  5. 开课吧Java课堂:是什么是比较函数?

    TreeSet和TreeMap都按排序顺序存储元素.然而,精确定义采用何种"排序顺序"的是比较函数. 通常在默认的情况下,这些类通过使用被Java称之为"自然顺序&quo ...

  6. 开课吧Java课堂:是什么TreeMap类

    TreeMap类通过使用树实现Map接口.TreeMap提供了按排序顺序存储关键字/值对的有效手段,同时允许快速检索.应该注意的是,不像散列映射,树映射保证它的元素按照关键字升序排序. 下面的Tree ...

  7. 开课吧Java课堂:什么是HashMap类

    HashMap类使用散列表实现Map接口.这允许一些基本操作如get( )和put( )的运行时间保持恒定,即便对大型集合,也是这样的. 下面的构造函数定义为: HashMap( ) HashMap( ...

  8. 开课吧Java课堂:如何将用户定义的类存储于Collection中

    为了简单,类集并没有被限制为只能存储内置的对象.完全相反的是,类集的能力是它能存储任何类型的对象,包括你所创建的类的对象.例如,考虑下面的例子,在这个例子中使用LinkedList存储信箱地址. // ...

  9. 开课吧Java课堂:如何使用迭代函数

    在通过迭代函数访问类集之前,必须得到一个迭代函数.每一个Collection类都提供一个iterator( )函数,该函数返回一个对类集头的迭代函数.通过使用这个迭代函数对象,可以访问类集中的每一个元 ...

最新文章

  1. 深度学习(6)构造简单的神经网络
  2. java myeclipse jar 导出问题
  3. 使用KNN模型进行多标签分类实战(Multilabel Classification)
  4. python获取列表中指定元素的下标
  5. 以太坊Oracle系列二:My Oracle
  6. c++-内存管理-G2.9
  7. SAP Leonardo 机器学习插件的安装
  8. WAF+SLB负载不均衡案例分享
  9. python 规则引擎 drools_Drools规则引擎入门demo
  10. linux 64位module内联汇编,@yuanbor: Linux内联汇编总结
  11. LINUX 游戏服务器之旅4_mongodb环境
  12. POJ训练计划3096_Surprising Strings(STL/map)
  13. python2.7 安装第三方库
  14. css 设置背景图片透明
  15. 假如我来架构12306网站(二) - 浅谈系统需求调研
  16. Ubuntu Firefox浏览器安装Flash插件
  17. 熊猫人表情包python 代码_Python实现表情包的代码实例
  18. UBUNTU开启CRONTAB日志记录及解决NO MTA INSTALLED, DISCARDING OUTPUT问题
  19. Java基础习题(四)
  20. C语言_钩子函数(回调函数)

热门文章

  1. MATLAB库函数radarvcd介绍
  2. JS编写自己的富文本编辑器
  3. [转]jQuery为控件添加水印文字
  4. android实现翻书效果(文本和图片的翻书)
  5. C# 怎样判断 datagridview 中的checkbox列是否被选中
  6. 离开,是一个新的开始
  7. Page.IsValid 属性
  8. Python 编程训练(3)
  9. c++中*是什么意思_int在python中什么意思
  10. java判断safari_js代码判断浏览器种类IE、FF、Opera、Safari、chrome及版本