课时86:接口基本定义
摘要:本次课程主要围绕Java中接口展开讲解。首先阐述接口的基本概念,即用于对外部隐藏全部实现细节,是一种比抽象类更严格的抽象类型,包含抽象方法与全局常量,后因Lambda表达式引入,其定义有所扩展 。
接着介绍接口的使用原则,如需要被子类实现、子类需复写接口中的抽象方法等,并通过代码示例展示具体实现过程。然后探讨接口实现多继承的特性以及由此带来的对象转型问题,同时讲解接口中方法的访问权限。之后分析抽象类与接口的关系以及接口多继承的情况。
最后说明接口在实际开发中的三种应用形式,帮助读者全面深入地理解接口在Java开发中的重要性和使用方法。
1. 接口的基本概念与定义
2. 接口的使用原则与实现示例
4. 抽象类与接口的关系及接口多继承
同学们,今天咱们来一起深入了解一下在Java实际开发中极为重要的概念——接口。在正式开始前,我得跟大家强调一点,当你能够熟练运用抽象类和接口进行程序设计的时候,那就说明你对面向对象的概念已经有了较为深刻的理解。
不过,达到这个程度需要通过大量的代码编写和实践才能实现,可别想着今天高兴一拍脑袋就能完全掌握了,这是不太现实的。
01、 接口的基本概念与定义
咱们先来看看接口的基本定义。抽象类相比于普通类,最大的优势在于可以控制子类对方法的复写。这确实是我们使用抽象类的主要原因之一,但是在抽象类里,可能还是会存在一些普通方法,而这些普通方法可能涉及到安全或者隐私相关的操作。
在开发过程中,如果想要把所有的实现细节都对外部隐藏起来,这时就可以借助接口来实现,这就是接口的主要概念。可能有些同学对这句话还不太理解,没关系,等我们学到分布式开发的时候,大家就能有更深刻的体会了。一般来说,涉及分布式开发的项目规模都不小,代码量非常庞大,不过这都是后话了。
简单来说,接口可以看作是一种“纯粹”的抽象。最初,接口里只包含抽象方法和全局常量,从这个角度看,它是一种比抽象类还要严格的抽象类型。
但是从 Jdk 1.8开始,随着Lambda表达式概念的引入,接口的定义也得到了扩展,除了抽象方法和全局常量,还可以定义普通方法和静态方法。虽然接口的定义有所放宽,但从设计的角度来讲,接口的组成还是应该以抽象方法和全局常量为主,这才是比较规范的。
在Java里,定义接口主要使用`interface`关键字。下面咱们来定义一个简单的接口。假设我们定义一个名为`message`的接口,这里有个问题大家要注意,抽象类和类本质上都是一种概念,但接口相对特殊一些。
如果接口和类的命名方式结构一样,仅从命名上很难区分哪个是类,哪个是接口。为了便于区分,通常会在接口名称前加上字母“I”,这个“I”其实就是“interface”的缩写。
Interface message{//定义一个接口 Public static final string INFO=www.Mldn.cn;全局常量 Public abstract string getInfo();//抽象方法
这样,我们就完成了一个接口的定义。看起来不难,但是接口有个很明显的问题,它没办法直接创建实例化对象。为什么呢?因为一旦创建了实例化对象,就意味着可以通过这个对象调用方法了,可接口里的抽象方法并没有具体的实现,所以不能创建实例化对象。
02、 接口的使用原则与实现示例
关于接口的使用,有这么几个原则:
第一,接口需要被子类实现,在Java里,实现接口用`implements`一个子类可以实现多个父接口;
第二,如果子类不是抽象类,那么必须复写接口里的所有抽象方法;
第三,接口对象可以通过子类对象的向上转型来进行实例化。
代码示例:定义一个类`messageTmp1`来实现` message`接口。
Class messagetemp1 implements Imessage{//实现了接口
但是写完之后,如果这个子类没有复写接口里的抽象方法,编译的时候就会报错,提示不是抽象类,并且没有复写`getInfo`这个抽象方法。所以,我们需要在子类里复写这个方法,比如`return "发送得到一个消息,秘密的消息,有人胖了(不是我)"` 。
接下来,在代码里我们可以这样操作:` Imessage msg = new MessageTmpl();
` ,然后可以通过` out.println(msg.getInfo());`
来调用方法,还能直接通过接口名调用全局常量,像 Imessage.INFO
。写完代码后编译并运行,看看能不能得到预期的结果。
Return“得到一个消息,秘密的消息,有人胖了(不是我)” out.println(msg.getInfo()); out.println(Imessage.INFO);
03、 接口实现多继承及对象转型问题
在Java中,使用接口还有一个很重要的原因,就是子类可以通过实现多个接口来实现多继承的概念。我们来定义一个新的接口`IChannel` ,假设它是一个消息通道相关的接口,里面定义一个抽象方法`boolean connect()
` ,方法实现里可以简单输出“消息发送通道已经成功建立”,并返回`true` 。
在使用这个接口的时候,可以这样写代码:`if (this.connect()) { // 执行一些操作 } else { // 处理连接失败的情况 }
` 。
Interface IChannel{ Public abstract boolean connect(){}; Class messageImp1 Implements IMessage,IChannel { Public string getInfo(){ `if (this.connect()) { Return“得到一个消息,秘密的消息,有人胖了(不是我)” Return“通道创建失败无法获取消息” Public Boolean connect(){ System.out.println (“消息发送通道已经成功建立”) Return true;
但是这个时候就需要考虑一个实际的情况了,关于对象的转型问题了。
咱们把这个接口和之前的` Imessage`接口结合起来看,假设` Messageimp2`这个子类同时实现` Imessage`和`Ichannel`两个接口,这样就实现了多继承。但是这里面存在一个对象转型的问题,大家要注意。
比如` Messageimp2`这个子类创建的对象,它既是` Messageimp2`类型的对象,同时也是` Ichannel`和` Imessage`接口的实例化对象,并且还是`Object`类的子类对象。这就涉及到向上转型的问题了,因为`Object`类可以接收所有的引用类型数据。
举个例子,代码可以这么写:` message msg = new messageImp1();
` ,` Ichannel chl =(IChannel)msg;`
,虽然` Message`和` Ichannel`这两个接口相互独立,没有直接关系,但因为Messageimpl()
子类实现了这两个接口,所以这两个接口的实例之间是可以转换的,不过这种转换仅限于通过这个子类去获取实例的时候。
在Java程序里面接口是不允许去继承父类的,所以接口绝对不会是Object的子类,但是根据之前的分析可以发现,Messageimpl是Object的子类,所以接口一定可以Object接收。另外,`Object`类对象可以接收接口对象,比如`Object Obj =Msg;//向上转型
`,更神奇的是,还可以进行` Ichannel Chan =(Ichannel)Obj;
`这样的转换,这是因为它们实际上都指向同一个子类对象。
Imessage msg = new messageImpl() Object obj =msg;//向上转型` Ichannel = (IChannel)msg;` Ichannel chan = ( Ichannel)obj; System.out.println(chan.connect())
Object类对象可以接收所有数据类型,包括基本数据类型、类对象、接口对象、数组。
再来说说接口中方法的访问权限。由于接口描述的是一个公共的定义标准,所以接口里所有抽象方法的访问权限默认都是`public` ,写不写`public`关键字效果是一样的。
比如说,定义两个接口,一个是完整定义,每个方法都明确写了`public`访问权限;另一个是简化定义,没有写访问权限,这两个接口本质上是完全一样的。不过在覆写接口方法的时候,必须使用`public`权限。在实际编写代码的时候,如果为了省事,可以不写访问权限,但如果从代码规范性的角度考虑,还是建议把访问权限写全。
04、 抽象类与接口的关系
还有一点要注意,在实际开发中,实现接口的有可能是抽象类。一个抽象类可以实现多个接口,而一个普通类只能继承一个抽象类,同时可以实现多个接口,但要注意继承和实现的顺序,需要先继承再实现。
比如说,定义一个抽象类`AbstractImp` ,继承某个抽象类(假设为`AbstractBase` )并实现` message`接口,像这样:` Abstract class databaseabstract {
。在这个抽象类里,如果定义一个方法getDatabaseConnection()
` 。
要注意,只有接口中的抽象方法可以省略`abstract`关键字,抽象类里是不允许省略的。在子类中就需要复写接口中的所有抽象方法,并且可以根据实际情况进行逻辑判断和处理。
Abstract class databaseabstract { Public abstract Boolean getDatabaseConnection(); Public Boolean getDatabaseConnection();
虽然接口无法继承一个父类,但是一个接口却可以通过extends继承若干个父接口:此时就叫接口的多继承,比如定义一个接口`MessageService` ,让它继承` message`和` Ichannel`两个接口,代码可以写成` Interface Iservice extends IMessage,IChannel{
。
这种接口多继承的情况在类继承里是不允许的,类继承只能继承一个父类。在实现`MessageService`接口的时候,需要复写它所继承的所有接口里的抽象方法。
Interface IChannel { Public Boolean connect(); Interface Iservice extends IMessage,IChannel{
最后,跟大家说一下接口在实际开发中的应用形式,一般有三种:
第一种是用于进行标准设置;
第二种是表示一种操作的能力;
第三种是在远程方法调用,也就是RPC分布式开发中使用,不过这部分内容我们之后再详细讲解。
总之,接口的概念在Java开发里非常重要,大家一定要理解透彻。