Java开发笔记(五十八)简单接口及其实现
前面介绍了抽象方法及抽象类的用法,看似解决了不确定行为的方法定义,既然叫唤动作允许声明为抽象方法,那么飞翔、游泳也能声明为抽象方法,并且鸡类涵盖的物种不够多,最好把这些行为动作扩展到鸟类这个群体,于是整个鸟类的成员方法都可以如法炮制了。可是这种做法也带来了一些弊端,包括但不限于:
1、能飞的动物不仅仅是鸟类,还有昆虫、蝙蝠等其它动物也能飞,难不成昆虫类、哺乳动物类也要自行声明飞翔方法?这么做显然产生了重复的方法定义。不然的话,要是把飞翔方法挪到更底层的动物类,一大群动物为了不沦为抽象类都得重写飞翔方法,比如鳄鱼、大象等根本不会飞的动物也要装模作样扑腾几下,实在是滑天下之大稽。
2、除了几种常见的鸟类为大众所熟知之外,大部分鸟类其实人们一时半刻叫不出它们的名字,倘若在路上偶遇一只鸟儿,难道因为不认识它就没法描述它的模样了吗?(如果鸟类是个抽象类,外部是不能创建鸟类实例的)
3、就算给整个动物类都添加了叫唤、飞翔、游泳这些抽象方法,并且费尽九牛二虎之力把所有派生而来的子类都实现了这三个抽象方法,也不意味着万事大吉。譬如青蛙擅长跳跃这个动作,哪天程序员突发奇想要给抽象的动物类补充跳跃方法,从而支持青蛙的跳跃行为,随之而来的代价便是让动物类的所有子类都重写跳跃方法,这样也太伤筋动骨了。
综上所述,抽象类解决不了层出不穷的问题,远非什么灵丹妙药,只能用于处理符合条件的特定要求。若想真正有效应对这些刁钻古怪的挑战,还得指望新的抽象技术,在Java编程中这就是接口。接口不从属于类,而是与类平级,类通过关键字class标识,而接口通过关键字interface来标识。由于接口是作为类的辅助角色出现,因此它在结构上与类比较相似,不过也有不少不同之处,举例如下:
1、凡是类都有构造方法,即便是抽象类也支持定义构造方法,但接口不允许定义构造方法,因为接口只用于声明某些行为动作,本身并非一个实体。
2、在Java8以前,接口内部的所有方法都必须是抽象方法,具体的方法内部代码有赖于该接口的实现类来补充。因为有这个强制规定,所以接口内部方法的abstract前缀可加可不加,即使不加abstract,编译器也会默认把该方法当作抽象方法。
3、至于接口内部的属性,则默认为终态属性,即添加了final前缀的成员属性。当然这个final前缀也是可加可不加的,即使不加final,编译器仍会默认把该属性当作终态属性。
按照上述的接口规定,再来编写一个定义了动物行为的接口代码,其中主要包括飞翔方法、游泳方法、奔跑方法等,详细的接口定义代码示例如下:
//定义一个接口。接口主要声明一些特定的行为方法
public interface Behavior { // 声明了一个抽象的飞翔方法。注意,接口内部的方法默认都是抽象方法,所以可以不用添加abstract前缀
public void fly();
//abstract public void fly(); // 这里的abstract可加可不加 // 声明了一个抽象的游泳方法
public void swim(); // 声明了一个抽象的奔跑方法
public void run(); // 接口内部的属性默认都是终态属性,所以可以不用添加final前缀
public String TAG = "动物世界";
//public final String TAG = "动物世界"; // 这里的final可加可不加 // 接口不允许定义构造方法。在Java8以前,接口内部的所有方法都必须是抽象方法
}
接着定义一个鹅类,它不但继承自Bird鸟类,而且实现了新的行为接口Behavior。注意子类继承父类的格式为“extends 父类名”,实现某个接口的格式则为“implements 接口名”,同时该类还要重写接口里的所有抽象方法。于是实现了行为接口的鹅类代码如下所示:
//定义一个实现了接口Behavior的鹅类。注意鹅类需要实现Behavior接口的所有抽象方法
public class Goose extends Bird implements Behavior { public Goose(String name, int sexType) {
super(name, sexType);
} // 实现了接口的fly方法
@Override
public void fly() {
System.out.println("鹅飞不高,也飞不远。");
} // 实现了接口的swim方法
@Override
public void swim() {
System.out.println("鹅,鹅,鹅,曲项向天歌。白毛浮绿水,红掌拨清波。");
} // 实现了接口的run方法
@Override
public void run() {
System.out.println("槛外萧声轻荡漾,沙间鹅步满蹒跚。");
}
}
对于外部来说,这个鹅类跟一般的类没啥区别,鹅类所实现的接口方法,在外部看来都是鹅类的成员方法,原来怎么调用现在依然怎么调用。下面是外部使用鹅类的代码例子:
// 演示简单接口的实现类用法
private static void testSimple() {
Goose goose = new Goose("家鹅", 0);
goose.fly(); // 实现了接口的fly方法
goose.swim(); // 实现了接口的swim方法
goose.run(); // 实现了接口的run方法
}
接口与类相比还有一个重大区别,在Java体系之中,每个类最多只能继承一个父类,不能同时继承多个类,也就是不允许多重继承。而接口不存在这方面的限制,某个类可以只实现一个接口,也可以同时实现两个接口、三个接口等等,待实现的接口名称之间以逗号分隔。例如除了飞翔、游泳、奔跑这三种动作之外,有些动物还擅长跳跃,比如青蛙、袋鼠等等,倘若在现有的Behavior接口中增加跳跃方法jump,那么包括Goose在内所有实现了Behavior的类都要重写jump方法,显然改造量巨大。现在借助接口的多重实现特性,完全可以另外定义新的行为接口Behavior2,在新接口中声明跳跃方法,那么只有实现Behavior2接口的类才需要重写jump方法。按此思路单独定义的新接口Behavior2代码见下:
//定义另一个行为接口
public interface Behavior2 { // 声明了一个抽象的跳跃方法
public void jump();
}
然后编写Frog蛙类的定义代码,这个蛙类同时实现了接口Behavior和Behavior2,这样它要重写Behavior的三个方法,以及Behavior2的跳跃方法。下面是一个蛙类代码的简单例子:
//定义一个实现了接口Behavior和Behavior2的蛙类。类只能继承一个,但接口可以实现多个
public class Frog implements Behavior, Behavior2 { // 实现了Behavior2接口的jump方法
@Override
public void jump() {
System.out.println("青蛙跳跃的技能叫做“蛙跳”");
} // 实现了Behavior接口的fly方法
@Override
public void fly() {
} // 实现了Behavior接口的swim方法
@Override
public void swim() {
System.out.println("青蛙游泳的技能叫做“蛙泳”");
} // 实现了Behavior接口的run方法
@Override
public void run() {
}
}
由于新增的jump方法属于新接口Behavior2,不属于原接口Behavior,因此实现了Behavior接口的鹅类代码无需任何修改,只有实现Behavior2的蛙类代码才需额外处理。当然这个特殊处理也仅限于蛙类的定义,对于外部而言,蛙类Frog仍是一个普通的类,外部调用它并没有什么两样,具体的调用代码示例如下:
// 演示某个类同时实现了多个接口
private static void testMultiple() {
Frog frog = new Frog();
frog.swim(); // 实现了Behavior接口的swim方法
frog.jump(); // 实现了Behavior2接口的run方法
}
更多Java技术文章参见《Java开发笔记(序)章节目录》
Java开发笔记(五十八)简单接口及其实现的更多相关文章
- Java开发笔记(十八)上下求索的while循环
循环是流程控制的又一重要结构,“白天-黑夜-白天-黑夜”属于时间上的循环,古人“年复一年.日复一日”的“日出而作.日落而息”便是每天周而复始的生活.计算机程序处理循环结构时,给定一段每次都要执行的代码 ...
- Java开发笔记(九十八)利用Callable启动线程
前面介绍了如何利用Runnable接口构建线程任务,该方式确实方便了线程代码的复用与共享,然而Runnable不像公共方法那样有返回值,也就无法将线程代码的处理结果传给外部,造成外部既不知晓该线程是否 ...
- Java学习笔记二十八:Java中的接口
Java中的接口 一:Java的接口: 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承 ...
- Java开发学习(二十八)----拦截器(Interceptor)详细解析
一.拦截器概念 讲解拦截器的概念之前,我们先看一张图: (1)浏览器发送一个请求会先到Tomcat的web服务器 (2)Tomcat服务器接收到请求以后,会去判断请求的是静态资源还是动态资源 (3)如 ...
- Java开发笔记(十五)短路逻辑运算的优势
前面提到逻辑运算只能操作布尔变量,这其实是不严谨的,因为经过Java编程实现,会发现“&”.“|”.“^”这几个逻辑符号竟然可以对数字进行运算.譬如下面的代码就直接对数字分别开展了“与”.“或 ...
- Java学习笔记(十八)——Java DTO
[前面的话] 在和技术人员的交流中,各种专业术语会出现,每次都是默默的记录下出现的术语,然后再去网上查看是什么意思.最近做项目,需要使用到DTO,然后学习一下吧. 这篇文章是关于Java DTO的,选 ...
- 【Java学习笔记之十八】Javadoc注释的用法
Javadoc注释的用法 Java 文档 // 注释一行/* ...... */ 注释若干行/** ...... */ 注释若干行,并写入 javadoc 文档 通常这种注释的多行写法如下: /*** ...
- 安卓开发笔记(十八):实现button按钮事件的三种方法
Android开发中有三种主要的方式用于设置View的点击事件,1.创建内部类:2.主类中实现OnClickListener接口:3.使用匿名内部类.这三种方式都用到了OnClickListener接 ...
- Java开发笔记(十六)非此即彼的条件分支
前面花了大量篇幅介绍布尔类型及相应的关系运算和逻辑运算,那可不仅仅是为了求真值或假值,更是为了通过布尔值控制流程的走向.在现实生活中,常常需要在岔路口抉择走去何方,往南还是往北,向东还是向西?在Jav ...
- Java开发笔记(十九)规律变化的for循环
前面介绍while循环时,有个名叫year的整型变量频繁出现,并且它是控制循环进出的关键要素.不管哪一种while写法,都存在三处与year有关的操作,分别是“year = 0”.“year<l ...
随机推荐
- mysql 水平分表
新建10张表,user_0,user_1,...user_9,方法不可串用,采用hash或取余法,获取要操作的表名,取值用对应存值的方法 1.hash取余法 public function part_ ...
- Android Studio 真机调试 连接手机
前提:adb环境已经配置 手机端: 1.打开手机开发者权限,”设置“ 中找到 “版本号”,连续多次点击,会提示打开“开发者”.我的是 “设置” --> "关于手机" --&g ...
- [转]Understanding OpenStack Authentication: Keystone PKI
The latest stable release of OpenStack, codenamed Grizzly, revolutionizes the way user authenticatio ...
- 搭建Windows故障转移群集
标签:SQL SERVER/MSSQL SERVER/数据库/DBA/windows 概述 本章内容主要讲述搭建windows故障转移群集 环境: 域服务器:windows server 2008 R ...
- 【从零开始搭建自己的.NET Core Api框架】(四)实战!带你半个小时实现接口的JWT授权验证
系列目录 一. 创建项目并集成swagger 1.1 创建 1.2 完善 二. 搭建项目整体架构 三. 集成轻量级ORM框架——SqlSugar 3.1 搭建环境 3.2 实战篇:利用SqlSuga ...
- [Swift]LeetCode72. 编辑距离 | Edit Distance
Given two words word1 and word2, find the minimum number of operations required to convert word1 to ...
- [Swift]LeetCode229. 求众数 II | Majority Element II
Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. Note: The a ...
- [Swift]LeetCode754. 到达终点数字 | Reach a Number
You are standing at position 0 on an infinite number line. There is a goal at position target. On ea ...
- apache(OS 10013)以一种访问权限不允许的方式做了一个访问套接字的尝试 ...
今天启动Apache时, 报了“(OS 10013)以一种访问权限不允许的方式做了一个访问套接字的尝试. : make_sock: could not bind to address 0.0.0.0: ...
- 开启SSH
开启 ssh 远程连接 1.修改 sshd_config 输入 sudo vim /etc/ssh/sshd_config 做如下修改 PermitRootLogin yes [需要把注释 #号去掉, ...