前面介绍了类的常见用法,令人感叹面向对象的强大,几乎日常生活中的所有事物,都可以抽象成Java的基类及其子类。然而抽象操作也有副作用,就是某个抽象而来的行为可能是不确定的,比如半夜鸡叫,如果是公鸡则必定“喔喔喔”地叫,如果是母鸡则必定“咯咯咯”地叫,可要是不能确定这只鸡是公鸡还是母鸡抑或小鸡,系统怎么知道它会怎么叫?落实到鸡类Chicken的定义代码中,它的call方法便无法给出具体的叫声了,尽管鸡类能够派生出公鸡类和母鸡类,再在公鸡类和母鸡类重写call方法,但是外部仍然可以创建鸡类的实例,接着调用鸡类实例的call方法,此时该期望这只鸡发出什么叫声呢?不管是让鸡类胡言乱语、语无伦次,还是让鸡类默不作声、噤若寒蝉,显然都与真实情况有很大出入。
由此可见,某些类其实并不能拿来直接使用,充其量只能算半成品,必须经过进一步的加工,形成最终的成品方能给外部调用。鉴于前述的鸡类存在叫唤这个不确定的方法,故而理应将它归入半成品之列;至于由鸡类派生而来的公鸡类与母鸡类,因为包括叫唤在内的每个方法都是明确的,所以它们才成为机能鉴权的完整类。在Java编程中,功能不确定的方法被称作抽象方法,而包含抽象方法的类受到牵连就变成了抽象类。在类的定义代码里面,通过关键字abstract来标识抽象方法及抽象类;凡是被abstract修饰的抽象方法,由于方法的具体实现并不明确,因此抽象方法没有花括号所包裹着的方法体;凡是被abstract修饰的抽象类,由于包含了至少一个抽象方法,因此不允许外部创建抽象类的实例,否则就会出现鸡类实例不知如何叫唤的尴尬。除此之外,抽象类还有下列两点需要注意:
1、abstract只能用来修饰抽象方法和抽象类,不可用于修饰成员属性,因为属性值本身就允许通过赋值来改变,无所谓抽象不抽象。
2、虽然抽象类依旧可以拥有构造方法,但它的构造方法并不能被外部直接调用,因为外部不允许通过构造方法来创建抽象类的实例,抽象类的构造方法只能提供给它的子类调用。
絮絮叨叨了这么多抽象概念,接着尝试把之前的鸡类改写成抽象类,修改后的抽象鸡类定义代码示例如下:

//演示抽象类的定义
abstract public class Chicken { // 定义一个名称属性
public String name;
// 定义一个性别属性
public int sex; // 定义一个抽象的叫唤方法。注意后面没有花括号,并且以分号结尾
abstract public void call(); // 即使抽象类定义了构造方法,外部也无法创建它的实例
public Chicken() {
} // Java只有抽象类和抽象方法,没有抽象属性的说法
//abstract public String cry;
}

然后分别编写继承自鸡类的公鸡类和母鸡类,其中鸡类的抽象方法call是必须在子类中重写的,只有这样,派生而来的子类才具备所有完善的行为动作;否则的话,这个子类仍旧是个尚未完工的半成品,依然属于抽象类的行列。下面是重写了call方法的公鸡类代码例子:

//定义一个继承自抽象鸡类的公鸡类
public class Cock extends Chicken { public Cock() {
// 公鸡的性别固定为雄性
sex = 0;
} // 重写了公鸡的叫唤方法。如果不重写父类的抽象方法,那么该子类仍旧为抽象类
public void call() {
System.out.println("喔喔喔");
}
}

同样重写了call方法的母鸡类代码如下所示:

//定义一个继承自抽象鸡类的母鸡类
public class Hen extends Chicken { public Hen() {
// 母鸡的性别固定为雌性
sex = 1;
} // 重写了母鸡的叫唤方法。如果不重写父类的抽象方法,那么该子类仍旧为抽象类
public void call() {
System.out.println("咯咯咯");
}
}

最后轮到外部调用各种鸡类了,对于外部而言,唯一的区别是外部不能创建抽象类的实例,其它子类的调用则跟从前一样没有变化。具体的外部调用代码见下:

		// 不能创建抽象类的实例,因为抽象类是个尚未完工的类
//Chicken chicken = new Chicken();
// 创建一个公鸡实例,公鸡类继承自抽象类Chicken
Cock cock = new Cock();
cock.call(); // 调用公鸡实例的叫唤方法
// 创建一个母鸡实例,母鸡类继承自抽象类Chicken
Hen hen = new Hen();
hen.call(); // 调用母鸡实例的叫唤方法

运行上面的调用代码,得到以下的日志结果,可见子类重写后的call方法正常工作。

喔喔喔
咯咯咯

  

更多Java技术文章参见《Java开发笔记(序)章节目录

Java开发笔记(五十七)因抽象方法而产生的抽象类的更多相关文章

  1. Java开发笔记(十七)各得其所的多路分支

    前面提到条件语句的标准格式为“if (条件) { /* 条件成立时的操作代码 */ } else { /* 条件不成立时的操作代码 */ }”,乍看之下仿佛只有两个分支,一个是条件成立时的分支,另一个 ...

  2. Java开发笔记(序)章节目录

    现将本博客的Java学习文章整理成以下笔记目录,方便查阅. 第一章 初识JavaJava开发笔记(一)第一个Java程序Java开发笔记(二)Java工程的帝国区划Java开发笔记(三)Java帝国的 ...

  3. Java开发笔记(三十七)利用正则串分割字符串

    前面介绍了处理字符串的常用方法,还有一种分割字符串的场景也很常见,也就是按照某个规则将字符串切割为若干子串.分割规则通常是指定某个分隔符,根据字符串内部的分隔符将字符串进行分割,例如逗号.空格等等都可 ...

  4. Java开发笔记(五十八)简单接口及其实现

    前面介绍了抽象方法及抽象类的用法,看似解决了不确定行为的方法定义,既然叫唤动作允许声明为抽象方法,那么飞翔.游泳也能声明为抽象方法,并且鸡类涵盖的物种不够多,最好把这些行为动作扩展到鸟类这个群体,于是 ...

  5. Java开发笔记(五十九)Java8之后的扩展接口

    前面介绍了接口的基本用法,有心的朋友可能注意到这么一句话“在Java8以前,接口内部的所有方法都必须是抽象方法”,如此说来,在Java8之后,接口的内部方法也可能不是抽象方法了吗?之所以Java8对接 ...

  6. Java开发笔记(六十五)集合:HashSet和TreeSet

    对于相同类型的一组数据,虽然Java已经提供了数组加以表达,但是数组的结构实在太简单了,第一它无法直接添加新元素,第二它只能按照线性排列,故而数组用于基本的操作倒还凑合,若要用于复杂的处理就无法胜任了 ...

  7. Java开发笔记(六十七)清单:ArrayList和LinkedList

    前面介绍了集合与映射两类容器,它们的共同特点是每个元素都是唯一的,并且采用二叉树方式的类型还自带有序性.然而这两个特点也存在弊端:其一,为啥内部元素必须是唯一的呢?像手机店卖出了两部Mate20,虽然 ...

  8. Java开发笔记(九十五)NIO配套的文件工具Files

    NIO不但引进了高效的文件通道,而且新增了更加好用的文件工具家族,包括路径组工具Paths.路径工具Path.文件组工具Files.先看路径组工具Paths,该工具提供了静态方法get,输入某个文件的 ...

  9. Java开发笔记(八十七)随机访问文件的读写

    前面介绍了字符流读写文件的两种方式,包括文件字符流和缓存字符流,但是它们的写操作都存在一个问题:不管是write方法还是append方法,都只能从文件开头写入,而不能追加到文件末尾或者在文件中间某个位 ...

随机推荐

  1. Vue 学习笔记 — 无法避免的dom操作

    简书 使用Vue了一段时间,感觉确实不错,"数据驱动视图"非常好用,大部分情况下都不需要关心dom,但是凡事都有例外,总有一些时候我们必须要直接对dom进行操作,比如下面这个例子: ...

  2. 解决idea导入项目后依赖报错问题

    1.在idea首页 Confige-->setting-->build,execution,deployment-->buildTool-->maven-->work o ...

  3. 【安富莱专题教程第5期】工程调试利器RTT实时数据传输组件,替代串口调试,速度飞快,可以在中断和多任务中随意调用

    说明:1.串口作为经典的调试方式已经存在好多年了,缺点是需要一个专门的硬件接口.现在有了SEGGER的RTT(已经发布有几年了),无需占用系统额外的硬件资源,而且速度超快,是替代串口调试的绝佳方式.2 ...

  4. Pycharm中配置鼠标悬停快速提示方法参数

    第一步: 第二步: 演示:

  5. [Swift]LeetCode267.回文全排列 II $ Palindrome Permutation II

    Given a string s, return all the palindromic permutations (without duplicates) of it. Return an empt ...

  6. [Swift]LeetCode315. 计算右侧小于当前元素的个数 | Count of Smaller Numbers After Self

    You are given an integer array nums and you have to return a new countsarray. The counts array has t ...

  7. [Swift]LeetCode401. 二进制手表 | Binary Watch

    A binary watch has 4 LEDs on the top which represent the hours (0-11), and the 6 LEDs on the bottom ...

  8. Ubuntu12.04中的虚拟机安装Ubuntu16.04,并实现远程控制16.04

    目录 1.设置网络连接 1.1 VMware虚拟机网络地址设置 1.2 设置虚拟机内Ubuntu16.04的网络模式 未开机状态下 开机状态下 1.3 查看虚拟机中Ubuntu16.04的IP 2.进 ...

  9. springboot中实现多数据源

    springboot中实现多数据源 1.什么场景需要多数据源 业务读写分离 业务分库 业务功能模块拆分多库 2.常见的多数据源的方案 按照数据源分别把mapper和entity放到不同的package ...

  10. Kubernetes 笔记 07 豌豆荚之旅(二)

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. Hi,大家好, ...