接口基本定义
抽象类与普通类的最大优势在于:可以实现对子类覆写方法的控制,但是在抽象类中依然保留有一些普通方法,而普通方法中可能会涉及到一些安全或隐私的问题。在进行开发的过程中,如果想要对外部隐藏全部的实现细节,就可以通过接口来描述。
接口可以理解为一个纯粹的抽象类(最原始的定义接口中只包含抽象方法与全局变量),从JDK1.8开始由于引入了Lambda表达式的概念,所以接口的定义也得到了加强,除了抽象方法与全局变量外,还可以定义普通方法或静态方法。
从设计本身的角度来将,接口中的组成还是应该以抽象方法和全局变量为主。
在Java中接口主要食用interface关键字来进行定义。
对于接口需要注意以下几点:
1、接口需要被子类实现(implements),一个子类可以实现多个父接口;
2、子类(如果不是抽象类)那么一定要覆写接口之中的全部抽象方法;
3、接口对象可以利用子类对象的向上转型
范例:定义接口
package 面向对象;
//由于类名称与接口名称的定义要求相同,所以为了区分出接口,接口名称前往往会加入I
interface IMessage{ //定义了一个接口
public static final String INFO = "www.mldn.cn"; //全局常量
public abstract String getInfo(); //抽象方法
}
class MessageImpl implements IMessage { //实现了接口
public String getInfo() {
return "得到一个消息,秘密的消息,有人胖了(不是我)。";
}
}
public class InterfaceDemo00 {
public static void main(String[] args) {
IMessage msg = new MessageImpl(); //向上转型
System.out.println(msg.getInfo()); //子类对象msg调用其getInfo()方法
System.out.println(IMessage.INFO); //类名调用静态属性
}
}
输出结果:
得到一个消息,秘密的消息,有人胖了(不是我)。
www.mldn.cn
关于接口的重要说明:
在Java中之所以使用接口的主要目的是一个子类可以实现多个接口,利用接口可以实现多继承的概念。
范例:观察子类实现多个父接口
package 面向对象;
//由于类名称与接口名称的定义要求相同,所以为了区分出接口,接口名称前往往会加入I
interface IMessage{ //定义了一个接口
public static final String INFO = "www.mldn.cn"; //全局常量
public abstract String getInfo(); //抽象方法
}
interface IChannel {
public abstract boolean connect(); //定义抽象方法
}
class MessageImpl implements IMessage, IChannel { //实现了接口
public String getInfo() {
if (this.connect()) {
return "得到一个消息,秘密的消息,有人胖了(不是我)。";
}
return "通道创建失败,无法获取消息。 ";
}
public boolean connect() {
System.out.println("消息发送通道已经成功建立。");
return true;
}
}
public class InterfaceDemo00 {
public static void main(String[] args) {
IMessage msg = new MessageImpl(); //向上转型
System.out.println(msg.getInfo()); //子类对象msg调用其getInfo()方法
System.out.println(IMessage.INFO); //类名调用静态属性
}
}
输出结果:
消息发送通道已经成功建立。
得到一个消息,秘密的消息,有人胖了(不是我)。
www.mldn.cn
但是这时就需要考虑一个实际的情况了,考虑转型问题
package 面向对象;
//由于类名称与接口名称的定义要求相同,所以为了区分出接口,接口名称前往往会加入I
interface IMessage{ //定义了一个接口
public static final String INFO = "www.mldn.cn"; //全局常量
public abstract String getInfo(); //抽象方法
}
interface IChannel {
public abstract boolean connect(); //定义抽象方法
}
class MessageImpl implements IMessage, IChannel { //实现了接口
public String getInfo() {
if (this.connect()) {
return "得到一个消息,秘密的消息,有人胖了(不是我)。";
}
return "通道创建失败,无法获取消息。 ";
}
public boolean connect() {
System.out.println("消息发送通道已经成功建立。");
return true;
}
}
public class InterfaceDemo00 {
public static void main(String[] args) {
IMessage msg = new MessageImpl(); //向上转型
IChannel chl = (IChannel)msg;
System.out.println(chl.connect()); //子类对象msg调用其getInfo()方法
}
}
消息发送通道已经成功建立。
true
由于MessageImpl子类实现了IMessage和IChannel两个接口,所以这个子类可以是这两个接口中任意一个接口的实例,从而表示此时这两个接口实例之间是可以转换的。
在Java程序中接口是不能继承父类的。所以接口绝对不会是Object的子类,但是根据之前的分析可以发现,MessageImpl是Object的子类,所以接口一定可以通过Object接收。
范例:接口与Object类有关系吗
package 面向对象;
import javax.swing.*;
//由于类名称与接口名称的定义要求相同,所以为了区分出接口,接口名称前往往会加入I
interface IMessage{ //定义了一个接口
public static final String INFO = "www.mldn.cn"; //全局常量
public abstract String getInfo(); //抽象方法
}
interface IChannel {
public abstract boolean connect(); //定义抽象方法
}
class MessageImpl implements IMessage, IChannel { //实现了接口
public String getInfo() {
if (this.connect()) {
return "得到一个消息,秘密的消息,有人胖了(不是我)。";
}
return "通道创建失败,无法获取消息。 ";
}
public boolean connect() {
System.out.println("消息发送通道已经成功建立。");
return true;
}
}
public class InterfaceDemo00 {
public static void main(String[] args) {
IMessage msg = new MessageImpl(); //向上转型
Object obj = msg; //向上转型
IChannel chl = (IChannel)obj; //向下转型
System.out.println(chl.connect()); //子类对象msg调用其getInfo()方法
}
}
输出结果:
消息发送通道已经成功建立。
true
Object类可以接收所有的数据类型,包括基本数据类型、类对象、接口对象、数组。
由于接口描述的是一个公共的定义标准,所以在
接口中所有的抽象方法的访问权限都是public,也即是写或者不写都是一样的
范例:下面的两个接口本质上是完全相同的
方法不写访问权限也是public,不是default,所以覆写的时候只能使用public;
接口虽然已经可以成功的进行了定义。但是在实际开发中,实现接口的可能是抽象类,一个抽象类可以实现多个接口,而一个普通类只能继承一个抽象类,并且可以实现,但是要求先继承后实现。
范例:子类先继承后实现
package 面向对象;
import javax.swing.*;
//由于类名称与接口名称的定义要求相同,所以为了区分出接口,接口名称前往往会加入I
interface IMessage{ //定义了一个接口
public static final String INFO = "www.mldn.cn"; //全局常量
public abstract String getInfo(); //抽象方法
}
interface IChannel {
//接口中可以省略abstract属性
public boolean connect(); //定义抽象方法
}
abstract class DatabaseAbstract { //定义一个抽象类
//接口中的abstract可以省略,而抽象类中不可以省略
//抽象类中不可以省略abstract属性
public abstract boolean getDatabaseConnection();
}
class MessageImpl extends DatabaseAbstract implements IMessage, IChannel { //实现了接口
@Override
public boolean getDatabaseConnection() {
return true;
}
public String getInfo() {
if (this.connect()) {
if (this.getDatabaseConnection()) {
return "数据库中得到一个消息,秘密的消息,有人胖了(不是我)。";
}else {
return "数据库消息无法访问";
}
}
return "通道创建失败,无法获取消息。 ";
}
public boolean connect() {
System.out.println("消息发送通道已经成功建立。");
return true;
}
}
public class InterfaceDemo00 {
public static void main(String[] args) {
IMessage msg = new MessageImpl(); //向上转型
System.out.println(msg.getInfo());
}
}
输出结果:
消息发送通道已经成功建立。
数据库中得到一个消息,秘密的消息,有人胖了(不是我)。
虽然接口无法继承一个父类,但是一个接口却可以通过extends实现若干个父接口,此时称为接口的多继承。
范例:实现接口多继承
package 面向对象;
interface IMessage01 {
public abstract String getInfo();
}
interface IChannel01 {
public boolean connect();
}
//extends在类继承上只能继承一个父类,但是接口上可以继承多个
interface IService extends IMessage01, IChannel01 {
public String service();
}
class MessageSevice implements IService {
public String getInfo() {
return null;
}
public boolean connect() {
return true;
}
public String service() {
return "获取消息服务。";
}
}
public class InterfaceDemo01 {
public static void main(String[] args) {
}
}
在实际的开发中,接口的使用往往有三种形式:
进行标准设置
表示一种操作的能力
暴露远程方法视图,这个一般都是在RPC分布式开发中使用