接口的定义与使用
当你可以灵活的使用抽象类和接口进行设计的时候,那么基本上就表示你面向对象的概念理解了。这一步需要大量的代码积累。
接口基本定义
抽象类与普通类相比的最大的优势在于:可以实现子类方法覆写的控制,在抽象类中会保留一些普通方法,
而这些普通方法里面可能会涉及到一些安全或者隐私的操作问题,那么在开发之中,如果想要对外隐藏全部的技术细节,则就可以使用接口来进行描述。
接口可以理解为一个纯粹的抽象类(最原始的定义接口之中是只包含抽象方法和全局常量的),但是JDK1.8开始引入了Lambda表达式的概念,接口的定义也得到了加强,除了抽象方法与全局常量之外,还可以定义普通方法或静态方法。
如果从设计本身来讲,接口之中组成还是应该以抽象方法和全局常量为主。
在Java中主要使用interface关键字来进行定义。
interface IMessage{
public static final String info = 'test'; //全局常量
public abstract String getInfo(); //抽象方法
}
由于类名称与接口定义要求相同,所以为了区分出接口接口名名称前往往加入大写字母I(Interface);
问题:此时的接口无法直接产生实例化对象,所以对于接口的使用原则如下:
- 接口需要被子类实现(implements),一个子类可以实现多个父接口;
- 子类(如果不是抽象类)那么一定要覆写接口中的全部抽象方法;
- 接口对象可以利用子类对象的向上转型进行实例化;
interface IMessage{
public static final String info = 'test'; //全局常量
public abstract String getInfo(); //抽象方法
}
class MessageImpl implements Imessage{ //实现接口
public String getInfo(){
return "test";
}
}
以上是接口的使用,但是Java中使用接口的主要目的是一个子类可以实现多个接口,利用接口可以实现多继承的概念;
interface IMessage{
public static final String info = 'test'; //全局常量
public abstract String getInfo(); //抽象方法
}
interface IChannel{
public abstract boolean connect();
}
class MessageImpl implements Imessage,IChannel{ //继承多个接口
public String getInfo(){
return "test";
}
public boolean connect(){
return true;
}
}
但是此时要考虑实际情况,关于对象的转型问题,此时子类对象可以实现任意父接口的转换。
在Java中接口是不允许继承父类的,所以接口绝对不会是Object的子类,所以接口可以使用Object接收。
Object类对象可以接收所有数据类型,包括基本数据类型、类对象、接口对象、数组。
接口描述的是一个公共定义标准,所以接口中所有抽象方法的访问权限都为public,也就是说写不写都一样(覆写的时候必须使用public);
接口虽然可以成功进行定义,在实际开发中实现接口的有可能是一个抽象类,一个抽象类可以实现多个接口,一个普通类只能够继承一个抽象类并且可以实现多个父接口,但要求先继承后实现;
接口中的abstract可省略,抽象类中不允许省略。虽然接口无法继承一个父类,但是接口可以通过extends继承若干个父接口,此时称为接口的多继承。
在实际开发中,接口的使用往往有三种形式:
- 进行标准设置;
- 表示一种操作能力;
- 暴露远程方法视图:这个一般都在RPC分布式开发中使用;
接口定义加强
接口最早的主要特点是全部由抽象方法和全局常量所组成,但是如果项目不涉及,就可能出现严重的问题;
接口的不当设计:最初时不敢保证接口设计足够完善,为了方便子类的方便,往往不会让子类直接继承接口,而是在中间增加一个抽象类:
但是从JDK1.8开始,为了解决接口设计的缺陷,在接口之中允许开发者定义普通方法,接口中的普通方法必须追加default声明,需要注意,该操作属于挽救功能,如果不是必须,不应作为必须的首选;
除了追加可追加普通方法外,还可以追加static方法,而static可以通过接口直接调用;
使用接口定义标准
对于接口而言在开发之中最为重要的应用就是进行标准的制定。
interface IUSB{
//定义USB标准
public boolean check();
public void work();
}
工厂设计模式(Factory)
对于接口而言必须由子类,并且之类可以通过对象的向上转型来获取接口的实例化对象,但是实例化过程中可能存在设计问题;
耦合问题:关键字new,以JVM设计为例,Java实现可移植性的关键在于:JVM,利用一个虚拟机来运行Java程序,所有的程序并不与具体的操作系统有任何的关联,而是由JVM来进行匹配;
所以良好的设计应避免耦合;
代理设计模式(Proxy)
代理设计的主要功能时可以帮助用户将所有的开发注意力只集中在核心业务功能的处理上,例如肚子饿,思考如何吃东西,
interface IEat{
public void get();
}
class EatReal implements IEat{
public void get(){
System.out.println("[真实主题]得到一份食物")
}
}
class EatProxy implements IEat{
//服务代理
private IEat eat; //为吃服务
public EatProxy(IEat eat){
//一定要有一个代理项
this.eat = eat;
}
public void get(){
this.prepare();
this.eat.get();
}
public void prepare(){
//准备过程
System.out.println("[代理主题]:购买食材");
System.out.println("[代理主题]:处理食材");
}
}
代理设计模式的主要设计特点有两个子类,其中一个子类是真是业务操作类,另外一个之类是代理业务操作类,没有代理业务操作,真实业务无法进行。
抽象类与接口区别
实际开发中可以发现抽象类和接口的定义形式十分相似,这一点从JDK1.8开始实际上就特别明显了,因为JDK1.8也可以定义default和static方法,但是这两者仍有明显的定义和使用区别;
No | 区别 | 抽象类 | 接口 |
---|---|---|---|
1 | 定义 | Abstract 抽象类名称{} | interface 接口名称{} |
2 | 组成 | 构造、普通方法、静态方法、全局常量、成员 | 抽象方法、全局常量、普通方法、static方法 |
3 | 权限 | 可以使用各种权限定义 | 只能使用public |
4 | 子类使用 | 子类通过extends关键字可以继承一个关键字 | 子类使用implements关键字可以实现多个接口 |
5 | 两者关系 | 抽象类可以实现若干个接口 | 接口不允许继承抽象类,但允许继承多个父接口 |
6 | 使用 | 1、抽象类或接口必须定义子类 2、子类一定要覆写抽象类或接口中的全部抽象方法 3、通过子类的向上转型实现抽象类或接口对象实例化 |
当抽象类和接口都可以使用时优先考虑接口,因为接口可以避免子类的单继承局限;
另外从一个正常设计角度而言,也需要先从接口来进行项目的整体设计;